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