xref: /AOO41X/main/xmloff/source/core/xmlehelp.cxx (revision 63bba73cc51e0afb45f8a8d578158724bb5afee8)
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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_xmloff.hxx"
26 #include <limits.h>
27 #include <tools/debug.hxx>
28 #include <tools/bigint.hxx>
29 #include <rtl/ustrbuf.hxx>
30 #include "xmlehelp.hxx"
31 
32 #ifndef _XMLOFF_XMTOKEN_HXX
33 #include <xmloff/xmltoken.hxx>
34 #endif
35 
36 using ::rtl::OUString;
37 using ::rtl::OUStringBuffer;
38 
39 using namespace ::xmloff::token;
40 
AddLength(sal_Int32 nValue,MapUnit eValueUnit,OUStringBuffer & rOut,MapUnit eOutUnit)41 void SvXMLExportHelper::AddLength( sal_Int32 nValue, MapUnit eValueUnit,
42                                    OUStringBuffer& rOut,
43                                    MapUnit eOutUnit )
44 {
45     // the sign is processed seperatly
46     if( nValue < 0 )
47     {
48         nValue = -nValue;
49         rOut.append( sal_Unicode('-') );
50     }
51 
52     // The new length is (nVal * nMul)/(nDiv*nFac*10)
53     sal_Int32 nMul = 1000;
54     sal_Int32 nDiv = 1;
55     sal_Int32 nFac = 100;
56     enum XMLTokenEnum eUnit = XML_TOKEN_INVALID;
57     switch( eValueUnit )
58     {
59     case MAP_TWIP:
60         switch( eOutUnit )
61         {
62         case MAP_100TH_MM:
63         case MAP_10TH_MM:
64             DBG_ASSERT( MAP_INCH == eOutUnit,
65                         "output unit not supported for twip values" );
66         case MAP_MM:
67             // 0.01mm = 0.57twip (exactly)
68             nMul = 25400;   // 25.4 * 1000
69             nDiv = 1440;    // 72 * 20;
70             nFac = 100;
71             eUnit = XML_UNIT_MM;
72             break;
73 
74         case MAP_CM:
75             // 0.001cm = 0.57twip (exactly)
76             nMul = 25400;   // 2.54 * 10000
77             nDiv = 1440;    // 72 * 20;
78             nFac = 1000;
79             eUnit = XML_UNIT_CM;
80             break;
81 
82         case MAP_POINT:
83             // 0.01pt = 0.2twip (exactly)
84             nMul = 1000;
85             nDiv = 20;
86             nFac = 100;
87             eUnit = XML_UNIT_PT;
88             break;
89 
90         case MAP_INCH:
91         default:
92             DBG_ASSERT( MAP_INCH == eOutUnit,
93                         "output unit not supported for twip values" );
94             // 0.0001in = 0.144twip (exactly)
95             nMul = 100000;
96             nDiv = 1440;    // 72 * 20;
97             nFac = 10000;
98             eUnit = XML_UNIT_INCH;
99             break;
100         }
101         break;
102 
103     case MAP_POINT:
104         // 1pt = 1pt (exactly)
105         DBG_ASSERT( MAP_POINT == eOutUnit,
106                     "output unit not supported for pt values" );
107         nMul = 10;
108         nDiv = 1;
109         nFac = 1;
110         eUnit = XML_UNIT_PT;
111         break;
112     case MAP_10TH_MM:
113     case MAP_100TH_MM:
114         {
115             long nFac2 = (MAP_100TH_MM == eValueUnit) ? 100 : 10;
116             switch( eOutUnit )
117             {
118             case MAP_100TH_MM:
119             case MAP_10TH_MM:
120                 DBG_ASSERT( MAP_INCH == eOutUnit,
121                             "output unit not supported for 1/100mm values" );
122             case MAP_MM:
123                 // 0.01mm = 1 mm/100 (exactly)
124                 nMul = 10;
125                 nDiv = 1;
126                 nFac = nFac2;
127                 eUnit = XML_UNIT_MM;
128                 break;
129 
130             case MAP_CM:
131                 // 0.001mm = 1 mm/100 (exactly)
132                 nMul = 10;
133                 nDiv = 1;   // 72 * 20;
134                 nFac = 10*nFac2;
135                 eUnit = XML_UNIT_CM;
136                 break;
137 
138             case MAP_POINT:
139                 // 0.01pt = 0.35 mm/100 (exactly)
140                 nMul = 72000;
141                 nDiv = 2540;
142                 nFac = nFac2;
143                 eUnit = XML_UNIT_PT;
144                 break;
145 
146             case MAP_INCH:
147             default:
148                 DBG_ASSERT( MAP_INCH == eOutUnit,
149                             "output unit not supported for 1/100mm values" );
150                 // 0.0001in = 0.254 mm/100 (exactly)
151                 nMul = 100000;
152                 nDiv = 2540;
153                 nFac = 100*nFac2;
154                 eUnit = XML_UNIT_INCH;
155                 break;
156             }
157             break;
158         }
159         default:
160             DBG_ASSERT( 0, "input unit not handled" );
161             break;
162     }
163 
164 
165     sal_Int32 nLongVal = 0;
166     sal_Bool bOutLongVal = sal_True;
167     if( nValue > SAL_MAX_INT32 / nMul )
168     {
169         // A big int is required for calculation
170         BigInt nBigVal( nValue );
171         nBigVal *= nMul;
172         nBigVal /= nDiv;
173         nBigVal += 5;
174         nBigVal /= 10;
175 
176         if( nBigVal.IsLong() )
177         {
178             // To convert the value into a string a sal_Int32 is sufficient
179             nLongVal = sal_Int32( nBigVal );
180         }
181         else
182         {
183             BigInt nBigFac( nFac );
184             BigInt nBig10( 10 );
185             rOut.append( (sal_Int32)(nBigVal / nBigFac) );
186             if( !(nBigVal % nBigFac).IsZero() )
187             {
188                 rOut.append( sal_Unicode('.') );
189                 while( nFac > 1 && !(nBigVal % nBigFac).IsZero() )
190                 {
191                     nFac /= 10;
192                     nBigFac = nFac;
193                     rOut.append( (sal_Int32)((nBigVal / nBigFac) % nBig10 ) );
194                 }
195             }
196             bOutLongVal = sal_False;
197         }
198     }
199     else
200     {
201         nLongVal = nValue * nMul;
202         nLongVal /= nDiv;
203         nLongVal += 5;
204         nLongVal /= 10;
205     }
206 
207     if( bOutLongVal )
208     {
209         rOut.append( (sal_Int32)(nLongVal / nFac) );
210         if( nFac > 1 && (nLongVal % nFac) != 0 )
211         {
212             rOut.append( sal_Unicode('.') );
213             while( nFac > 1 && (nLongVal % nFac) != 0 )
214             {
215                 nFac /= 10;
216                 rOut.append( (sal_Int32)((nLongVal / nFac) % 10) );
217             }
218         }
219     }
220 
221     if( eUnit != XML_TOKEN_INVALID )
222         rOut.append( GetXMLToken(eUnit) );
223 }
224 
AddPercentage(sal_Int32 nValue,OUStringBuffer & rOut)225 void SvXMLExportHelper::AddPercentage( sal_Int32 nValue, OUStringBuffer& rOut )
226 {
227     rOut.append( nValue );
228     rOut.append( sal_Unicode('%' ) );
229 }
230 
GetConversionFactor(::rtl::OUStringBuffer & rUnit,const MapUnit eCoreUnit,const MapUnit eDestUnit)231 double SvXMLExportHelper::GetConversionFactor(::rtl::OUStringBuffer& rUnit,
232     const MapUnit eCoreUnit, const MapUnit eDestUnit)
233 {
234     double fRetval(1.0);
235     rUnit.setLength(0L);
236 
237     if(eCoreUnit != eDestUnit)
238     {
239         enum XMLTokenEnum eUnit = XML_TOKEN_INVALID;
240 
241         switch(eCoreUnit)
242         {
243             case MAP_TWIP:
244             {
245                 switch(eDestUnit)
246                 {
247                     case MAP_100TH_MM:
248                     case MAP_10TH_MM:
249                     {
250                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for twip values");
251                     }
252                     case MAP_MM:
253                     {
254                         // 0.01mm = 0.57twip (exactly)
255                         fRetval = ((25400.0 / 1440.0) / 1000.0);
256                         eUnit = XML_UNIT_MM;
257                         break;
258                     }
259                     case MAP_CM:
260                     {
261                         // 0.001cm = 0.57twip (exactly)
262                         fRetval = ((25400.0 / 1440.0) / 10000.0);
263                         eUnit = XML_UNIT_CM;
264                         break;
265                     }
266                     case MAP_POINT:
267                     {
268                         // 0.01pt = 0.2twip (exactly)
269                         fRetval = ((1000.0 / 20.0) / 1000.0);
270                         eUnit = XML_UNIT_PT;
271                         break;
272                     }
273                     case MAP_INCH:
274                     default:
275                     {
276                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for twip values");
277                         // 0.0001in = 0.144twip (exactly)
278                         fRetval = ((100000.0 / 1440.0) / 100000.0);
279                         eUnit = XML_UNIT_INCH;
280                         break;
281                     }
282                 }
283                 break;
284             }
285             case MAP_POINT:
286             {
287                 switch(eDestUnit)
288                 {
289                     case MAP_MM:
290                         // 1mm = 72 / 25.4 pt (exactly)
291                         fRetval = ( 25.4 / 72.0 );
292                         eUnit = XML_UNIT_MM;
293                         break;
294 
295                     case MAP_CM:
296                         // 1cm = 72 / 2.54 pt (exactly)
297                         fRetval = ( 2.54 / 72.0 );
298                         eUnit = XML_UNIT_CM;
299                         break;
300 
301                     case MAP_TWIP:
302                         // 1twip = 72 / 1440 pt (exactly)
303                         fRetval = 20.0;     // 1440.0 / 72.0
304                         eUnit = XML_UNIT_PC;
305                         break;
306 
307                     case MAP_INCH:
308                     default:
309                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for pt values");
310                         // 1in = 72 pt (exactly)
311                         fRetval = ( 1.0 / 72.0 );
312                         eUnit = XML_UNIT_INCH;
313                         break;
314                 }
315                 break;
316             }
317             case MAP_10TH_MM:
318             {
319                 switch(eDestUnit)
320                 {
321                     case MAP_100TH_MM:
322                     case MAP_10TH_MM:
323                     {
324                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for 1/100mm values");
325                     }
326                     case MAP_MM:
327                     {
328                         // 0.01mm = 1 mm/100 (exactly)
329                         fRetval = ((10.0 / 1.0) / 100.0);
330                         eUnit = XML_UNIT_MM;
331                         break;
332                     }
333                     case MAP_CM:
334                     {
335                         // 0.001mm = 1 mm/100 (exactly)
336                         fRetval = ((10.0 / 1.0) / 1000.0);
337                         eUnit = XML_UNIT_CM;
338                         break;
339                     }
340                     case MAP_POINT:
341                     {
342                         // 0.01pt = 0.35 mm/100 (exactly)
343                         fRetval = ((72000.0 / 2540.0) / 100.0);
344                         eUnit = XML_UNIT_PT;
345                         break;
346                     }
347                     case MAP_INCH:
348                     default:
349                     {
350                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for 1/100mm values");
351                         // 0.0001in = 0.254 mm/100 (exactly)
352                         fRetval = ((100000.0 / 2540.0) / 10000.0);
353                         eUnit = XML_UNIT_INCH;
354                         break;
355                     }
356                 }
357                 break;
358             }
359             case MAP_100TH_MM:
360             {
361                 switch(eDestUnit)
362                 {
363                     case MAP_100TH_MM:
364                     case MAP_10TH_MM:
365                     {
366                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for 1/100mm values");
367                     }
368                     case MAP_MM:
369                     {
370                         // 0.01mm = 1 mm/100 (exactly)
371                         fRetval = ((10.0 / 1.0) / 1000.0);
372                         eUnit = XML_UNIT_MM;
373                         break;
374                     }
375                     case MAP_CM:
376                     {
377                         // 0.001mm = 1 mm/100 (exactly)
378                         fRetval = ((10.0 / 1.0) / 10000.0);
379                         eUnit = XML_UNIT_CM;
380                         break;
381                     }
382                     case MAP_POINT:
383                     {
384                         // 0.01pt = 0.35 mm/100 (exactly)
385                         fRetval = ((72000.0 / 2540.0) / 1000.0);
386                         eUnit = XML_UNIT_PT;
387                         break;
388                     }
389                     case MAP_INCH:
390                     default:
391                     {
392                         DBG_ASSERT(MAP_INCH == eDestUnit, "output unit not supported for 1/100mm values");
393                         // 0.0001in = 0.254 mm/100 (exactly)
394                         fRetval = ((100000.0 / 2540.0) / 100000.0);
395                         eUnit = XML_UNIT_INCH;
396                         break;
397                     }
398                 }
399                 break;
400             }
401             default:
402                 DBG_ERROR("xmloff::SvXMLExportHelper::GetConversionFactor(), illegal eCoreUnit value!");
403                 break;
404         }
405 
406         if(eUnit != XML_TOKEN_INVALID)
407             rUnit.append(GetXMLToken(eUnit));
408     }
409 
410     return fRetval;
411 }
412 
GetUnitFromString(const::rtl::OUString & rString,MapUnit eDefaultUnit)413 MapUnit SvXMLExportHelper::GetUnitFromString(const ::rtl::OUString& rString, MapUnit eDefaultUnit)
414 {
415     sal_Int32 nPos = 0;
416     sal_Int32 nLen = rString.getLength();
417     MapUnit eRetUnit = eDefaultUnit;
418 
419     // skip white space
420     while( nPos < nLen && sal_Unicode(' ') == rString[nPos] )
421         nPos++;
422 
423     // skip negative
424     if( nPos < nLen && sal_Unicode('-') == rString[nPos] )
425         nPos++;
426 
427     // skip number
428     while( nPos < nLen && sal_Unicode('0') <= rString[nPos] && sal_Unicode('9') >= rString[nPos] )
429         nPos++;
430 
431     if( nPos < nLen && sal_Unicode('.') == rString[nPos] )
432     {
433         nPos++;
434         while( nPos < nLen && sal_Unicode('0') <= rString[nPos] && sal_Unicode('9') >= rString[nPos] )
435             nPos++;
436     }
437 
438     // skip white space
439     while( nPos < nLen && sal_Unicode(' ') == rString[nPos] )
440         nPos++;
441 
442     if( nPos < nLen )
443     {
444         switch(rString[nPos])
445         {
446             case sal_Unicode('%') :
447             {
448                 eRetUnit = MAP_RELATIVE;
449                 break;
450             }
451             case sal_Unicode('c'):
452             case sal_Unicode('C'):
453             {
454                 if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('m')
455                     || rString[nPos+1] == sal_Unicode('M')))
456                     eRetUnit = MAP_CM;
457                 break;
458             }
459             case sal_Unicode('e'):
460             case sal_Unicode('E'):
461             {
462                 // CSS1_EMS or CSS1_EMX later
463                 break;
464             }
465             case sal_Unicode('i'):
466             case sal_Unicode('I'):
467             {
468                 if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('n')
469                     || rString[nPos+1] == sal_Unicode('n')))
470                     eRetUnit = MAP_INCH;
471                 break;
472             }
473             case sal_Unicode('m'):
474             case sal_Unicode('M'):
475             {
476                 if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('m')
477                     || rString[nPos+1] == sal_Unicode('M')))
478                     eRetUnit = MAP_MM;
479                 break;
480             }
481             case sal_Unicode('p'):
482             case sal_Unicode('P'):
483             {
484                 if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('t')
485                     || rString[nPos+1] == sal_Unicode('T')))
486                     eRetUnit = MAP_POINT;
487                 if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('c')
488                     || rString[nPos+1] == sal_Unicode('C')))
489                     eRetUnit = MAP_TWIP;
490                 break;
491             }
492         }
493     }
494 
495     return eRetUnit;
496 }
497