LibreOffice Module sax (master) 1
converter.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
21
22#include <com/sun/star/i18n/UnicodeType.hpp>
23#include <com/sun/star/util/DateTime.hpp>
24#include <com/sun/star/util/Date.hpp>
25#include <com/sun/star/util/Duration.hpp>
26#include <com/sun/star/util/Time.hpp>
27#include <optional>
28
29#include <rtl/ustrbuf.hxx>
30#include <rtl/math.hxx>
31#include <rtl/character.hxx>
32#include <sal/log.hxx>
33#include <o3tl/string_view.hxx>
36#include <osl/diagnose.h>
37#include <tools/long.hxx>
38
39#include <algorithm>
40#include <string_view>
41
42using namespace com::sun::star;
43using namespace com::sun::star::uno;
44using namespace com::sun::star::util;
45using namespace ::com::sun::star::i18n;
46
47
48namespace sax {
49
50const std::string_view gpsMM = "mm";
51const std::string_view gpsCM = "cm";
52const std::string_view gpsPT = "pt";
53const std::string_view gpsINCH = "in";
54const std::string_view gpsPC = "pc";
55
57
58static sal_Int64 toInt64_WithLength(const sal_Unicode * str, sal_Int16 radix, sal_Int32 nStrLength )
59{
60 return rtl_ustr_toInt64_WithLength(str, radix, nStrLength);
61}
62static sal_Int64 toInt64_WithLength(const char * str, sal_Int16 radix, sal_Int32 nStrLength )
63{
64 return rtl_str_toInt64_WithLength(str, radix, nStrLength);
65}
66
67namespace
68{
69o3tl::Length Measure2O3tlUnit(sal_Int16 nUnit)
70{
71 switch (nUnit)
72 {
73 case MeasureUnit::TWIP:
74 return o3tl::Length::twip;
75 case MeasureUnit::POINT:
76 return o3tl::Length::pt;
77 case MeasureUnit::MM_10TH:
78 return o3tl::Length::mm10;
79 case MeasureUnit::MM_100TH:
81 case MeasureUnit::MM:
82 return o3tl::Length::mm;
83 case MeasureUnit::CM:
84 return o3tl::Length::cm;
85 default:
86 SAL_WARN("sax", "unit not supported for length");
87 [[fallthrough]];
88 case MeasureUnit::INCH:
89 return o3tl::Length::in;
90 }
91}
92
93std::string_view Measure2UnitString(sal_Int16 nUnit)
94{
95 switch (nUnit)
96 {
97 case MeasureUnit::TWIP:
98 return gpsPC; // ??
99 case MeasureUnit::POINT:
100 return gpsPT;
101 case MeasureUnit::MM_10TH:
102 case MeasureUnit::MM_100TH:
103 return {};
104 case MeasureUnit::MM:
105 return gpsMM;
106 case MeasureUnit::CM:
107 return gpsCM;
108 case MeasureUnit::INCH:
109 default:
110 return gpsINCH;
111 }
112}
113
114template <typename V> bool wordEndsWith(V string, std::string_view expected)
115{
116 V substr = string.substr(0, expected.size());
117 return std::equal(substr.begin(), substr.end(), expected.begin(), expected.end(),
118 [](sal_uInt32 c1, sal_uInt32 c2) { return rtl::toAsciiLowerCase(c1) == c2; })
119 && (string.size() == expected.size() || string[expected.size()] == ' ');
120}
121
122}
123
125template<typename V>
126static bool lcl_convertMeasure( sal_Int32& rValue,
127 V rString,
128 sal_Int16 nTargetUnit /* = MeasureUnit::MM_100TH */,
129 sal_Int32 nMin /* = SAL_MIN_INT32 */,
130 sal_Int32 nMax /* = SAL_MAX_INT32 */ )
131{
132 bool bNeg = false;
133 double nVal = 0;
134
135 sal_Int32 nPos = 0;
136 sal_Int32 const nLen = rString.size();
137
138 // skip white space
139 while( (nPos < nLen) && (rString[nPos] <= ' ') )
140 nPos++;
141
142 if( nPos < nLen && '-' == rString[nPos] )
143 {
144 bNeg = true;
145 nPos++;
146 }
147
148 // get number
149 while( nPos < nLen &&
150 '0' <= rString[nPos] &&
151 '9' >= rString[nPos] )
152 {
153 // TODO: check overflow!
154 nVal *= 10;
155 nVal += (rString[nPos] - '0');
156 nPos++;
157 }
158 if( nPos < nLen && '.' == rString[nPos] )
159 {
160 nPos++;
161 double nDiv = 1.;
162
163 while( nPos < nLen &&
164 '0' <= rString[nPos] &&
165 '9' >= rString[nPos] )
166 {
167 // TODO: check overflow!
168 nDiv *= 10;
169 nVal += ( static_cast<double>(rString[nPos] - '0') / nDiv );
170 nPos++;
171 }
172 }
173
174 // skip white space
175 while( (nPos < nLen) && (rString[nPos] <= ' ') )
176 nPos++;
177
178 if( nPos < nLen )
179 {
180
181 if( MeasureUnit::PERCENT == nTargetUnit )
182 {
183 if( '%' != rString[nPos] )
184 return false;
185 }
186 else if( MeasureUnit::PIXEL == nTargetUnit )
187 {
188 if( nPos + 1 >= nLen ||
189 ('p' != rString[nPos] &&
190 'P' != rString[nPos])||
191 ('x' != rString[nPos+1] &&
192 'X' != rString[nPos+1]) )
193 return false;
194 }
195 else
196 {
197 OSL_ENSURE( MeasureUnit::TWIP == nTargetUnit || MeasureUnit::POINT == nTargetUnit ||
198 MeasureUnit::MM_100TH == nTargetUnit || MeasureUnit::MM_10TH == nTargetUnit ||
199 MeasureUnit::PIXEL == nTargetUnit, "unit is not supported");
200
202
203 if( MeasureUnit::TWIP == nTargetUnit )
204 {
205 switch (rtl::toAsciiLowerCase<sal_uInt32>(rString[nPos]))
206 {
207 case u'c':
208 if (wordEndsWith(rString.substr(nPos + 1), "m"))
209 eFrom = o3tl::Length::cm;
210 break;
211 case u'i':
212 if (wordEndsWith(rString.substr(nPos + 1), "n"))
213 eFrom = o3tl::Length::in;
214 break;
215 case u'm':
216 if (wordEndsWith(rString.substr(nPos + 1), "m"))
217 eFrom = o3tl::Length::mm;
218 break;
219 case u'p':
220 if (wordEndsWith(rString.substr(nPos + 1), "t"))
221 eFrom = o3tl::Length::pt;
222 else if (wordEndsWith(rString.substr(nPos + 1), "c"))
223 eFrom = o3tl::Length::pc;
224 break;
225 }
226 }
227 else if( MeasureUnit::MM_100TH == nTargetUnit || MeasureUnit::MM_10TH == nTargetUnit )
228 {
229 switch (rtl::toAsciiLowerCase<sal_uInt32>(rString[nPos]))
230 {
231 case u'c':
232 if (wordEndsWith(rString.substr(nPos + 1), "m"))
233 eFrom = o3tl::Length::cm;
234 break;
235 case u'i':
236 if (wordEndsWith(rString.substr(nPos + 1), "n"))
237 eFrom = o3tl::Length::in;
238 break;
239 case u'm':
240 if (wordEndsWith(rString.substr(nPos + 1), "m"))
241 eFrom = o3tl::Length::mm;
242 break;
243 case u'p':
244 if (wordEndsWith(rString.substr(nPos + 1), "t"))
245 eFrom = o3tl::Length::pt;
246 else if (wordEndsWith(rString.substr(nPos + 1), "c"))
247 eFrom = o3tl::Length::pc;
248 else if (wordEndsWith(rString.substr(nPos + 1), "x"))
249 eFrom = o3tl::Length::px;
250 break;
251 }
252 }
253 else if( MeasureUnit::POINT == nTargetUnit )
254 {
255 if (wordEndsWith(rString.substr(nPos), "pt"))
256 eFrom = o3tl::Length::pt;
257 }
258
259 if (eFrom == o3tl::Length::invalid)
260 return false;
261
262 // TODO: check overflow
263 nVal = o3tl::convert(nVal, eFrom, Measure2O3tlUnit(nTargetUnit));
264 }
265 }
266
267 nVal += .5;
268 if( bNeg )
269 nVal = -nVal;
270
271 if( nVal <= static_cast<double>(nMin) )
272 rValue = nMin;
273 else if( nVal >= static_cast<double>(nMax) )
274 rValue = nMax;
275 else
276 rValue = static_cast<sal_Int32>(nVal);
277
278 return true;
279}
280
282bool Converter::convertMeasure( sal_Int32& rValue,
283 std::u16string_view rString,
284 sal_Int16 nTargetUnit /* = MeasureUnit::MM_100TH */,
285 sal_Int32 nMin /* = SAL_MIN_INT32 */,
286 sal_Int32 nMax /* = SAL_MAX_INT32 */ )
287{
288 return lcl_convertMeasure(rValue, rString, nTargetUnit, nMin, nMax);
289}
290
292bool Converter::convertMeasure( sal_Int32& rValue,
293 std::string_view rString,
294 sal_Int16 nTargetUnit /* = MeasureUnit::MM_100TH */,
295 sal_Int32 nMin /* = SAL_MIN_INT32 */,
296 sal_Int32 nMax /* = SAL_MAX_INT32 */ )
297{
298 return lcl_convertMeasure(rValue, rString, nTargetUnit, nMin, nMax);
299}
300
301
303void Converter::convertMeasure( OUStringBuffer& rBuffer,
304 sal_Int32 nMeasure,
305 sal_Int16 nSourceUnit /* = MeasureUnit::MM_100TH */,
306 sal_Int16 nTargetUnit /* = MeasureUnit::INCH */ )
307{
308 if( nSourceUnit == MeasureUnit::PERCENT )
309 {
310 OSL_ENSURE( nTargetUnit == MeasureUnit::PERCENT,
311 "MeasureUnit::PERCENT only maps to MeasureUnit::PERCENT!" );
312
313 rBuffer.append( nMeasure );
314 rBuffer.append( '%' );
315
316 return;
317 }
318 sal_Int64 nValue(nMeasure); // extend to 64-bit first to avoid overflow
319 // the sign is processed separately
320 if (nValue < 0)
321 {
322 nValue = -nValue;
323 rBuffer.append( '-' );
324 }
325
327 int nFac = 100; // used to get specific number of decimals (2 by default)
328 std::string_view psUnit;
329 switch( nSourceUnit )
330 {
331 case MeasureUnit::TWIP:
332 eFrom = o3tl::Length::twip;
333 switch( nTargetUnit )
334 {
335 case MeasureUnit::MM_100TH:
336 case MeasureUnit::MM_10TH:
337 OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,"output unit not supported for twip values" );
338 [[fallthrough]];
339 case MeasureUnit::MM:
340 eTo = o3tl::Length::mm;
341 nFac = 100;
342 psUnit = gpsMM;
343 break;
344
345 case MeasureUnit::CM:
346 eTo = o3tl::Length::cm;
347 nFac = 1000;
348 psUnit = gpsCM;
349 break;
350
351 case MeasureUnit::POINT:
352 eTo = o3tl::Length::pt;
353 nFac = 100;
354 psUnit = gpsPT;
355 break;
356
357 case MeasureUnit::INCH:
358 default:
359 OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,
360 "output unit not supported for twip values" );
361 nFac = 10000;
362 psUnit = gpsINCH;
363 break;
364 }
365 break;
366
367 case MeasureUnit::POINT:
368 // 1pt = 1pt (exactly)
369 OSL_ENSURE( MeasureUnit::POINT == nTargetUnit,
370 "output unit not supported for pt values" );
371 eFrom = eTo = o3tl::Length::pt;
372 nFac = 1;
373 psUnit = gpsPT;
374 break;
375 case MeasureUnit::MM_10TH:
376 case MeasureUnit::MM_100TH:
377 {
378 int nFac2 = (MeasureUnit::MM_100TH == nSourceUnit) ? 100 : 10;
379 eFrom = Measure2O3tlUnit(nSourceUnit);
380 switch( nTargetUnit )
381 {
382 case MeasureUnit::MM_100TH:
383 case MeasureUnit::MM_10TH:
384 OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,
385 "output unit not supported for 1/100mm values" );
386 [[fallthrough]];
387 case MeasureUnit::MM:
388 eTo = o3tl::Length::mm;
389 nFac = nFac2;
390 psUnit = gpsMM;
391 break;
392
393 case MeasureUnit::CM:
394 eTo = o3tl::Length::cm;
395 nFac = 10*nFac2;
396 psUnit = gpsCM;
397 break;
398
399 case MeasureUnit::POINT:
400 eTo = o3tl::Length::pt;
401 nFac = nFac2;
402 psUnit = gpsPT;
403 break;
404
405 case MeasureUnit::INCH:
406 default:
407 OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,
408 "output unit not supported for 1/100mm values" );
409 nFac = 100*nFac2;
410 psUnit = gpsINCH;
411 break;
412 }
413 break;
414 }
415 default:
416 OSL_ENSURE(false, "sax::Converter::convertMeasure(): "
417 "source unit not supported");
418 break;
419 }
420
421 nValue = o3tl::convert(nValue * nFac, eFrom, eTo);
422
423 rBuffer.append( static_cast<sal_Int64>(nValue / nFac) );
424 if (nFac > 1 && (nValue % nFac) != 0)
425 {
426 rBuffer.append( '.' );
427 while (nFac > 1 && (nValue % nFac) != 0)
428 {
429 nFac /= 10;
430 rBuffer.append( static_cast<sal_Int32>((nValue / nFac) % 10) );
431 }
432 }
433
434 if (psUnit.length() > 0)
435 rBuffer.appendAscii(psUnit.data(), psUnit.length());
436}
437
439bool Converter::convertBool( bool& rBool, std::u16string_view rString )
440{
441 rBool = rString == u"true";
442
443 return rBool || (rString == u"false");
444}
445
447bool Converter::convertBool( bool& rBool, std::string_view rString )
448{
449 rBool = rString == "true";
450
451 return rBool || (rString == "false");
452}
453
455void Converter::convertBool( OUStringBuffer& rBuffer, bool bValue )
456{
457 rBuffer.append( bValue );
458}
459
461bool Converter::convertPercent( sal_Int32& rPercent, std::u16string_view rString )
462{
463 return convertMeasure( rPercent, rString, MeasureUnit::PERCENT );
464}
465
467bool Converter::convertPercent( sal_Int32& rPercent, std::string_view rString )
468{
469 return convertMeasure( rPercent, rString, MeasureUnit::PERCENT );
470}
471
473void Converter::convertPercent( OUStringBuffer& rBuffer, sal_Int32 nValue )
474{
475 rBuffer.append( nValue );
476 rBuffer.append( '%' );
477}
478
480bool Converter::convertMeasurePx( sal_Int32& rPixel, std::u16string_view rString )
481{
482 return convertMeasure( rPixel, rString, MeasureUnit::PIXEL );
483}
484
486bool Converter::convertMeasurePx( sal_Int32& rPixel, std::string_view rString )
487{
488 return convertMeasure( rPixel, rString, MeasureUnit::PIXEL );
489}
490
492void Converter::convertMeasurePx( OUStringBuffer& rBuffer, sal_Int32 nValue )
493{
494 rBuffer.append( nValue );
495 rBuffer.append( 'p' );
496 rBuffer.append( 'x' );
497}
498
499static int lcl_gethex( int nChar )
500{
501 if( nChar >= '0' && nChar <= '9' )
502 return nChar - '0';
503 else if( nChar >= 'a' && nChar <= 'f' )
504 return nChar - 'a' + 10;
505 else if( nChar >= 'A' && nChar <= 'F' )
506 return nChar - 'A' + 10;
507 else
508 return 0;
509}
510
512template<typename V>
513static bool lcl_convertColor( sal_Int32& rColor, V rValue )
514{
515 if( rValue.size() != 7 || rValue[0] != '#' )
516 return false;
517
518 rColor = lcl_gethex( rValue[1] ) * 16 + lcl_gethex( rValue[2] );
519 rColor <<= 8;
520
521 rColor |= lcl_gethex( rValue[3] ) * 16 + lcl_gethex( rValue[4] );
522 rColor <<= 8;
523
524 rColor |= lcl_gethex( rValue[5] ) * 16 + lcl_gethex( rValue[6] );
525
526 return true;
527}
528
530bool Converter::convertColor( sal_Int32& rColor, std::u16string_view rValue )
531{
532 return lcl_convertColor(rColor, rValue);
533}
534
536bool Converter::convertColor( sal_Int32& rColor, std::string_view rValue )
537{
538 return lcl_convertColor(rColor, rValue);
539}
540
541const char aHexTab[] = "0123456789abcdef";
542
544void Converter::convertColor( OUStringBuffer& rBuffer, sal_Int32 nColor )
545{
546 rBuffer.append( '#' );
547
548 sal_uInt8 nCol = static_cast<sal_uInt8>(nColor >> 16);
549 rBuffer.append( sal_Unicode( aHexTab[ nCol >> 4 ] ) );
550 rBuffer.append( sal_Unicode( aHexTab[ nCol & 0xf ] ) );
551
552 nCol = static_cast<sal_uInt8>(nColor >> 8);
553 rBuffer.append( sal_Unicode( aHexTab[ nCol >> 4 ] ) );
554 rBuffer.append( sal_Unicode( aHexTab[ nCol & 0xf ] ) );
555
556 nCol = static_cast<sal_uInt8>(nColor);
557 rBuffer.append( sal_Unicode( aHexTab[ nCol >> 4 ] ) );
558 rBuffer.append( sal_Unicode( aHexTab[ nCol & 0xf ] ) );
559}
560
562bool Converter::convertNumber( sal_Int32& rValue,
563 std::u16string_view aString,
564 sal_Int32 nMin, sal_Int32 nMax )
565{
566 rValue = 0;
567 sal_Int64 nNumber = 0;
568 bool bRet = convertNumber64(nNumber,aString,nMin,nMax);
569 if ( bRet )
570 rValue = static_cast<sal_Int32>(nNumber);
571 return bRet;
572}
573
575bool Converter::convertNumber( sal_Int32& rValue,
576 std::string_view aString,
577 sal_Int32 nMin, sal_Int32 nMax )
578{
579 rValue = 0;
580 sal_Int64 nNumber = 0;
581 bool bRet = convertNumber64(nNumber,aString,nMin,nMax);
582 if ( bRet )
583 rValue = static_cast<sal_Int32>(nNumber);
584 return bRet;
585}
586
588template<typename V>
589static bool lcl_convertNumber64( sal_Int64& rValue,
590 V aString,
591 sal_Int64 nMin, sal_Int64 nMax )
592{
593 sal_Int32 nPos = 0;
594 sal_Int32 const nLen = aString.size();
595
596 // skip white space
597 while( (nPos < nLen) && (aString[nPos] <= ' ') )
598 nPos++;
599
600 sal_Int32 nNumberStartPos = nPos;
601
602 if( nPos < nLen && '-' == aString[nPos] )
603 {
604 nPos++;
605 }
606
607 // get number
608 while( nPos < nLen &&
609 '0' <= aString[nPos] &&
610 '9' >= aString[nPos] )
611 {
612 nPos++;
613 }
614
615 rValue = toInt64_WithLength(aString.data() + nNumberStartPos, 10, nPos - nNumberStartPos);
616
617 if( rValue < nMin )
618 rValue = nMin;
619 else if( rValue > nMax )
620 rValue = nMax;
621
622 return ( nPos == nLen && rValue >= nMin && rValue <= nMax );
623}
624
626bool Converter::convertNumber64( sal_Int64& rValue,
627 std::u16string_view aString,
628 sal_Int64 nMin, sal_Int64 nMax )
629{
630 return lcl_convertNumber64(rValue, aString, nMin, nMax);
631}
632
634bool Converter::convertNumber64( sal_Int64& rValue,
635 std::string_view aString,
636 sal_Int64 nMin, sal_Int64 nMax )
637{
638 return lcl_convertNumber64(rValue, aString, nMin, nMax);
639}
640
641
643void Converter::convertDouble( OUStringBuffer& rBuffer,
644 double fNumber,
645 bool bWriteUnits,
646 sal_Int16 nSourceUnit,
647 sal_Int16 nTargetUnit)
648{
649 if(MeasureUnit::PERCENT == nSourceUnit)
650 {
651 OSL_ENSURE( nTargetUnit == MeasureUnit::PERCENT, "MeasureUnit::PERCENT only maps to MeasureUnit::PERCENT!" );
652 ::rtl::math::doubleToUStringBuffer( rBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
653 if(bWriteUnits)
654 rBuffer.append('%');
655 }
656 else
657 {
658 OUStringBuffer sUnit;
659 double fFactor = GetConversionFactor(sUnit, nSourceUnit, nTargetUnit);
660 if(fFactor != 1.0)
661 fNumber *= fFactor;
662 ::rtl::math::doubleToUStringBuffer( rBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
663 if(bWriteUnits)
664 rBuffer.append(sUnit);
665 }
666}
667
669void Converter::convertDouble( OUStringBuffer& rBuffer, double fNumber)
670{
671 ::rtl::math::doubleToUStringBuffer( rBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
672}
673
675bool Converter::convertDouble(double& rValue,
676 std::u16string_view rString, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
677{
678 if (!convertDouble(rValue, rString))
679 return false;
680
681 OUStringBuffer sUnit;
682 // fdo#48969: switch source and target because factor is used to divide!
683 double const fFactor =
684 GetConversionFactor(sUnit, nTargetUnit, nSourceUnit);
685 if(fFactor != 1.0 && fFactor != 0.0)
686 rValue /= fFactor;
687 return true;
688}
689
691bool Converter::convertDouble(double& rValue,
692 std::string_view rString, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
693{
694 if (!convertDouble(rValue, rString))
695 return false;
696
697 OStringBuffer sUnit;
698 // fdo#48969: switch source and target because factor is used to divide!
699 double const fFactor =
700 GetConversionFactor(sUnit, nTargetUnit, nSourceUnit);
701 if(fFactor != 1.0 && fFactor != 0.0)
702 rValue /= fFactor;
703 return true;
704}
705
707bool Converter::convertDouble(double& rValue, std::u16string_view rString)
708{
709 rtl_math_ConversionStatus eStatus;
710 rValue = rtl_math_uStringToDouble(rString.data(),
711 rString.data() + rString.size(),
712 /*cDecSeparator*/'.', /*cGroupSeparator*/',',
713 &eStatus, nullptr);
714 return ( eStatus == rtl_math_ConversionStatus_Ok );
715}
716
718bool Converter::convertDouble(double& rValue, std::string_view rString)
719{
720 rtl_math_ConversionStatus eStatus;
721 rValue = rtl_math_stringToDouble(rString.data(),
722 rString.data() + rString.size(),
723 /*cDecSeparator*/'.', /*cGroupSeparator*/',',
724 &eStatus, nullptr);
725 return ( eStatus == rtl_math_ConversionStatus_Ok );
726}
727
729void Converter::convertAngle(OUStringBuffer& rBuffer, sal_Int16 const nAngle,
731{
733 {
734 // wrong, but backward compatible with OOo/LO < 4.4
735 rBuffer.append(static_cast<sal_Int32>(nAngle));
736 }
737 else
738 { // OFFICE-3774 tdf#89475 write valid ODF 1.2 angle; needs LO 4.4 to import
739 double fAngle(double(nAngle) / 10.0);
740 ::sax::Converter::convertDouble(rBuffer, fAngle);
741 rBuffer.append("deg");
742 }
743}
744
746bool Converter::convertAngle(sal_Int16& rAngle, std::u16string_view rString,
747 bool const isWrongOOo10thDegAngle)
748{
749 // ODF 1.1 leaves it undefined what the number means, but ODF 1.2 says it's
750 // degrees, while OOo has historically used 10th of degrees :(
751 // So import degrees when we see the "deg" suffix but continue with 10th of
752 // degrees for now for the sake of existing OOo/LO documents, until the
753 // new versions that can read "deg" suffix are widely deployed and we can
754 // start to write the "deg" suffix.
755 sal_Int32 nValue(0);
756 double fValue(0.0);
757 bool bRet = ::sax::Converter::convertDouble(fValue, rString);
758 if (std::u16string_view::npos != rString.find(u"deg"))
759 {
760 nValue = fValue * 10.0;
761 }
762 else if (std::u16string_view::npos != rString.find(u"grad"))
763 {
764 nValue = (fValue * 9.0 / 10.0) * 10.0;
765 }
766 else if (std::u16string_view::npos != rString.find(u"rad"))
767 {
768 nValue = basegfx::rad2deg<10>(fValue);
769 }
770 else // no explicit unit
771 {
772 if (isWrongOOo10thDegAngle)
773 {
774 nValue = fValue; // wrong, but backward compatible with OOo/LO < 7.0
775 }
776 else
777 {
778 nValue = fValue * 10.0; // ODF 1.2
779 }
780 }
781 // limit to valid range [0..3600]
782 nValue = nValue % 3600;
783 if (nValue < 0)
784 {
785 nValue += 3600;
786 }
787 assert(0 <= nValue && nValue <= 3600);
788 if (bRet)
789 {
790 rAngle = sal::static_int_cast<sal_Int16>(nValue);
791 }
792 return bRet;
793}
794
796bool Converter::convertAngle(sal_Int16& rAngle, std::string_view rString,
797 bool const isWrongOOo10thDegAngle)
798{
799 // ODF 1.1 leaves it undefined what the number means, but ODF 1.2 says it's
800 // degrees, while OOo has historically used 10th of degrees :(
801 // So import degrees when we see the "deg" suffix but continue with 10th of
802 // degrees for now for the sake of existing OOo/LO documents, until the
803 // new versions that can read "deg" suffix are widely deployed and we can
804 // start to write the "deg" suffix.
805 sal_Int32 nValue(0);
806 double fValue(0.0);
807 bool bRet = ::sax::Converter::convertDouble(fValue, rString);
808 if (std::string_view::npos != rString.find("deg"))
809 {
810 nValue = fValue * 10.0;
811 }
812 else if (std::string_view::npos != rString.find("grad"))
813 {
814 nValue = (fValue * 9.0 / 10.0) * 10.0;
815 }
816 else if (std::string_view::npos != rString.find("rad"))
817 {
818 nValue = basegfx::rad2deg<10>(fValue);
819 }
820 else // no explicit unit
821 {
822 if (isWrongOOo10thDegAngle)
823 {
824 nValue = fValue; // wrong, but backward compatible with OOo/LO < 7.0
825 }
826 else
827 {
828 nValue = fValue * 10.0; // ODF 1.2
829 }
830 }
831 // limit to valid range [0..3600]
832 nValue = nValue % 3600;
833 if (nValue < 0)
834 {
835 nValue += 3600;
836 }
837 assert(0 <= nValue && nValue <= 3600);
838 if (bRet)
839 {
840 rAngle = sal::static_int_cast<sal_Int16>(nValue);
841 }
842 return bRet;
843}
844
846void Converter::convertDuration(OUStringBuffer& rBuffer,
847 const double fTime)
848{
849 double fValue = fTime;
850
851 // take care of negative durations as specified in:
852 // XML Schema, W3C Working Draft 07 April 2000, section 3.2.6.1
853 if (fValue < 0.0)
854 {
855 rBuffer.append('-');
856 fValue = - fValue;
857 }
858
859 rBuffer.append( "PT" );
860 fValue *= 24;
861 double fHoursValue = ::rtl::math::approxFloor (fValue);
862 fValue -= fHoursValue;
863 fValue *= 60;
864 double fMinsValue = ::rtl::math::approxFloor (fValue);
865 fValue -= fMinsValue;
866 fValue *= 60;
867 double fSecsValue = ::rtl::math::approxFloor (fValue);
868 fValue -= fSecsValue;
869 double fNanoSecsValue;
870 if (fValue > 0.00000000001)
871 fNanoSecsValue = ::rtl::math::round( fValue, XML_MAXDIGITSCOUNT_TIME - 5);
872 else
873 fNanoSecsValue = 0.0;
874
875 if (fNanoSecsValue == 1.0)
876 {
877 fNanoSecsValue = 0.0;
878 fSecsValue += 1.0;
879 }
880 if (fSecsValue >= 60.0)
881 {
882 fSecsValue -= 60.0;
883 fMinsValue += 1.0;
884 }
885 if (fMinsValue >= 60.0)
886 {
887 fMinsValue -= 60.0;
888 fHoursValue += 1.0;
889 }
890
891 if (fHoursValue < 10)
892 rBuffer.append( '0');
893 rBuffer.append( sal_Int32( fHoursValue));
894 rBuffer.append( 'H');
895 if (fMinsValue < 10)
896 rBuffer.append( '0');
897 rBuffer.append( sal_Int32( fMinsValue));
898 rBuffer.append( 'M');
899 if (fSecsValue < 10)
900 rBuffer.append( '0');
901 rBuffer.append( sal_Int32( fSecsValue));
902 if (fNanoSecsValue > 0.0)
903 {
904 OUString aNS( ::rtl::math::doubleToUString( fValue,
905 rtl_math_StringFormat_F, XML_MAXDIGITSCOUNT_TIME - 5, '.',
906 true));
907 if ( aNS.getLength() > 2 )
908 {
909 rBuffer.append( '.');
910 rBuffer.append( aNS.subView(2) ); // strip "0."
911 }
912 }
913 rBuffer.append( 'S');
914}
915
917template<typename V>
918static bool convertDurationHelper(double& rfTime, V pStr)
919{
920 // negative time duration?
921 bool bIsNegativeDuration = false;
922 if ( '-' == (*pStr) )
923 {
924 bIsNegativeDuration = true;
925 pStr++;
926 }
927
928 if ( *pStr != 'P' && *pStr != 'p' ) // duration must start with "P"
929 return false;
930 pStr++;
931
932 OUStringBuffer sDoubleStr;
933 bool bSuccess = true;
934 bool bDone = false;
935 bool bTimePart = false;
936 bool bIsFraction = false;
937 sal_Int32 nDays = 0;
938 sal_Int32 nHours = 0;
939 sal_Int32 nMins = 0;
940 sal_Int32 nSecs = 0;
941 sal_Int32 nTemp = 0;
942
943 while ( bSuccess && !bDone )
944 {
945 sal_Unicode c = *(pStr++);
946 if ( !c ) // end
947 bDone = true;
948 else if ( '0' <= c && '9' >= c )
949 {
950 if ( nTemp >= SAL_MAX_INT32 / 10 )
951 bSuccess = false;
952 else
953 {
954 if ( !bIsFraction )
955 {
956 nTemp *= 10;
957 nTemp += (c - u'0');
958 }
959 else
960 {
961 sDoubleStr.append(c);
962 }
963 }
964 }
965 else if ( bTimePart )
966 {
967 if ( c == 'H' || c == 'h' )
968 {
969 nHours = nTemp;
970 nTemp = 0;
971 }
972 else if ( c == 'M' || c == 'm')
973 {
974 nMins = nTemp;
975 nTemp = 0;
976 }
977 else if ( (c == ',') || (c == '.') )
978 {
979 nSecs = nTemp;
980 nTemp = 0;
981 bIsFraction = true;
982 sDoubleStr = "0.";
983 }
984 else if ( c == 'S' || c == 's' )
985 {
986 if ( !bIsFraction )
987 {
988 nSecs = nTemp;
989 nTemp = 0;
990 sDoubleStr = "0.0";
991 }
992 }
993 else
994 bSuccess = false; // invalid character
995 }
996 else
997 {
998 if ( c == 'T' || c == 't' ) // "T" starts time part
999 bTimePart = true;
1000 else if ( c == 'D' || c == 'd')
1001 {
1002 nDays = nTemp;
1003 nTemp = 0;
1004 }
1005 else if ( c == 'Y' || c == 'y' || c == 'M' || c == 'm' )
1006 {
1008
1009 OSL_FAIL( "years or months in duration: not implemented");
1010 bSuccess = false;
1011 }
1012 else
1013 bSuccess = false; // invalid character
1014 }
1015 }
1016
1017 if ( bSuccess )
1018 {
1019 if ( nDays )
1020 nHours += nDays * 24; // add the days to the hours part
1021 double fHour = nHours;
1022 double fMin = nMins;
1023 double fSec = nSecs;
1024 double fFraction = o3tl::toDouble(sDoubleStr);
1025 double fTempTime = fHour / 24;
1026 fTempTime += fMin / (24 * 60);
1027 fTempTime += fSec / (24 * 60 * 60);
1028 fTempTime += fFraction / (24 * 60 * 60);
1029
1030 // negative duration?
1031 if ( bIsNegativeDuration )
1032 {
1033 fTempTime = -fTempTime;
1034 }
1035
1036 rfTime = fTempTime;
1037 }
1038 return bSuccess;
1039}
1040
1042bool Converter::convertDuration(double& rfTime,
1043 std::string_view rString)
1044{
1045 std::string_view aTrimmed = o3tl::trim(rString);
1046 const char* pStr = aTrimmed.data();
1047
1048 return convertDurationHelper(rfTime, pStr);
1049}
1050
1052void Converter::convertDuration(OUStringBuffer& rBuffer,
1053 const ::util::Duration& rDuration)
1054{
1055 if (rDuration.Negative)
1056 {
1057 rBuffer.append('-');
1058 }
1059 rBuffer.append('P');
1060 const bool bHaveDate(rDuration.Years != 0 ||
1061 rDuration.Months != 0 ||
1062 rDuration.Days != 0);
1063 if (rDuration.Years)
1064 {
1065 rBuffer.append(static_cast<sal_Int32>(rDuration.Years));
1066 rBuffer.append('Y');
1067 }
1068 if (rDuration.Months)
1069 {
1070 rBuffer.append(static_cast<sal_Int32>(rDuration.Months));
1071 rBuffer.append('M');
1072 }
1073 if (rDuration.Days)
1074 {
1075 rBuffer.append(static_cast<sal_Int32>(rDuration.Days));
1076 rBuffer.append('D');
1077 }
1078 if ( rDuration.Hours != 0
1079 || rDuration.Minutes != 0
1080 || rDuration.Seconds != 0
1081 || rDuration.NanoSeconds != 0 )
1082 {
1083 rBuffer.append('T'); // time separator
1084 if (rDuration.Hours)
1085 {
1086 rBuffer.append(static_cast<sal_Int32>(rDuration.Hours));
1087 rBuffer.append('H');
1088 }
1089 if (rDuration.Minutes)
1090 {
1091 rBuffer.append(static_cast<sal_Int32>(rDuration.Minutes));
1092 rBuffer.append('M');
1093 }
1094 if (rDuration.Seconds != 0 || rDuration.NanoSeconds != 0)
1095 {
1096 // seconds must not be omitted (i.e. ".42S" is not valid)
1097 rBuffer.append(static_cast<sal_Int32>(rDuration.Seconds));
1098 if (rDuration.NanoSeconds)
1099 {
1100 OSL_ENSURE(rDuration.NanoSeconds < 1000000000,"NanoSeconds cannot be more than 999 999 999");
1101 rBuffer.append('.');
1102 std::ostringstream ostr;
1103 ostr.fill('0');
1104 ostr.width(9);
1105 ostr << rDuration.NanoSeconds;
1106 rBuffer.appendAscii(ostr.str().c_str());
1107 }
1108 rBuffer.append('S');
1109 }
1110 }
1111 else if (!bHaveDate)
1112 {
1113 // zero duration: XMLSchema-2 says there must be at least one component
1114 rBuffer.append('0');
1115 rBuffer.append('D');
1116 }
1117}
1118
1119namespace {
1120
1121enum Result { R_NOTHING, R_OVERFLOW, R_SUCCESS };
1122
1123}
1124
1125template <typename V>
1126static Result
1128 size_t & io_rnPos, sal_Int32 & o_rNumber)
1129{
1130 size_t nPos(io_rnPos);
1131
1132 while (nPos < rString.size())
1133 {
1134 const typename V::value_type c = rString[nPos];
1135 if (('0' > c) || (c > '9'))
1136 break;
1137 ++nPos;
1138 }
1139
1140 if (io_rnPos == nPos) // read something?
1141 {
1142 o_rNumber = -1;
1143 return R_NOTHING;
1144 }
1145
1146 const sal_Int64 nTemp = toInt64_WithLength(rString.data() + io_rnPos, 10, nPos - io_rnPos);
1147
1148 const bool bOverflow = (nTemp >= SAL_MAX_INT32);
1149
1150 io_rnPos = nPos;
1151 o_rNumber = nTemp;
1152 return bOverflow ? R_OVERFLOW : R_SUCCESS;
1153}
1154
1155template<typename V>
1156static Result
1158 V rString, size_t & io_rnPos,
1159 sal_Int32 & o_rNumber)
1160{
1161 bool bOverflow(false);
1162 sal_Int64 nTemp(0);
1163 size_t nPos(io_rnPos);
1164 OSL_ENSURE(maxDigits >= 0, "negative amount of digits makes no sense");
1165
1166 while (nPos < rString.size())
1167 {
1168 const sal_Unicode c = rString[nPos];
1169 if (('0' <= c) && (c <= '9'))
1170 {
1171 if (maxDigits > 0)
1172 {
1173 nTemp *= 10;
1174 nTemp += (c - u'0');
1175 if (nTemp >= SAL_MAX_INT32)
1176 {
1177 bOverflow = true;
1178 }
1179 --maxDigits;
1180 }
1181 }
1182 else
1183 {
1184 break;
1185 }
1186 ++nPos;
1187 }
1188
1189 if (io_rnPos == nPos) // read something?
1190 {
1191 o_rNumber = -1;
1192 return R_NOTHING;
1193 }
1194
1195 io_rnPos = nPos;
1196 o_rNumber = nTemp;
1197 return bOverflow ? R_OVERFLOW : R_SUCCESS;
1198}
1199
1200template<typename V>
1201static bool
1202readDurationT(V rString, size_t & io_rnPos)
1203{
1204 if ((io_rnPos < rString.size()) &&
1205 (rString[io_rnPos] == 'T' || rString[io_rnPos] == 't'))
1206 {
1207 ++io_rnPos;
1208 return true;
1209 }
1210 return false;
1211}
1212
1213template<typename V>
1214static bool
1216 size_t & io_rnPos, sal_Int32 & io_rnTemp, bool & io_rbTimePart,
1217 sal_Int32 & o_rnTarget, const sal_Unicode cLower, const sal_Unicode cUpper)
1218{
1219 if (io_rnPos < rString.size())
1220 {
1221 if (cLower == rString[io_rnPos] || cUpper == rString[io_rnPos])
1222 {
1223 ++io_rnPos;
1224 if (-1 != io_rnTemp)
1225 {
1226 o_rnTarget = io_rnTemp;
1227 io_rnTemp = -1;
1228 if (!io_rbTimePart)
1229 {
1230 io_rbTimePart = readDurationT(rString, io_rnPos);
1231 }
1232 return (R_OVERFLOW !=
1233 readUnsignedNumber(rString, io_rnPos, io_rnTemp));
1234 }
1235 else
1236 {
1237 return false;
1238 }
1239 }
1240 }
1241 return true;
1242}
1243
1244template <typename V>
1245static bool convertDurationHelper(util::Duration& rDuration, V string)
1246{
1247 size_t nPos(0);
1248
1249 bool bIsNegativeDuration(false);
1250 if (!string.empty() && ('-' == string[0]))
1251 {
1252 bIsNegativeDuration = true;
1253 ++nPos;
1254 }
1255
1256 if (nPos < string.size()
1257 && string[nPos] != 'P' && string[nPos] != 'p') // duration must start with "P"
1258 {
1259 return false;
1260 }
1261
1262 ++nPos;
1263
1265 sal_Int32 nTemp(-1);
1266 bool bTimePart(false); // have we read 'T'?
1267 bool bSuccess(false);
1268 sal_Int32 nYears(0);
1269 sal_Int32 nMonths(0);
1270 sal_Int32 nDays(0);
1271 sal_Int32 nHours(0);
1272 sal_Int32 nMinutes(0);
1273 sal_Int32 nSeconds(0);
1274 sal_Int32 nNanoSeconds(0);
1275
1276 bTimePart = readDurationT(string, nPos);
1277 bSuccess = (R_SUCCESS == readUnsignedNumber(string, nPos, nTemp));
1278
1279 if (!bTimePart && bSuccess)
1280 {
1281 bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1282 nYears, 'y', 'Y');
1283 }
1284
1285 if (!bTimePart && bSuccess)
1286 {
1287 bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1288 nMonths, 'm', 'M');
1289 }
1290
1291 if (!bTimePart && bSuccess)
1292 {
1293 bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1294 nDays, 'd', 'D');
1295 }
1296
1297 if (bTimePart)
1298 {
1299 if (-1 == nTemp) // a 'T' must be followed by a component
1300 {
1301 bSuccess = false;
1302 }
1303
1304 if (bSuccess)
1305 {
1306 bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1307 nHours, 'h', 'H');
1308 }
1309
1310 if (bSuccess)
1311 {
1312 bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1313 nMinutes, 'm', 'M');
1314 }
1315
1316 // eeek! seconds are icky.
1317 if ((nPos < string.size()) && bSuccess)
1318 {
1319 if (string[nPos] == '.' ||
1320 string[nPos] == ',')
1321 {
1322 ++nPos;
1323 if (-1 != nTemp)
1324 {
1325 nSeconds = nTemp;
1326 nTemp = -1;
1327 const sal_Int32 nStart(nPos);
1328 bSuccess = readUnsignedNumberMaxDigits(9, string, nPos, nTemp) == R_SUCCESS;
1329 if ((nPos < string.size()) && bSuccess)
1330 {
1331 if (-1 != nTemp)
1332 {
1333 nNanoSeconds = nTemp;
1334 sal_Int32 nDigits = nPos - nStart;
1335 assert(nDigits >= 0);
1336 for (; nDigits < 9; ++nDigits)
1337 {
1338 nNanoSeconds *= 10;
1339 }
1340 nTemp=-1;
1341 if ('S' == string[nPos] || 's' == string[nPos])
1342 {
1343 ++nPos;
1344 }
1345 else
1346 {
1347 bSuccess = false;
1348 }
1349 }
1350 else
1351 {
1352 bSuccess = false;
1353 }
1354 }
1355 }
1356 else
1357 {
1358 bSuccess = false;
1359 }
1360 }
1361 else if ('S' == string[nPos] || 's' == string[nPos])
1362 {
1363 ++nPos;
1364 if (-1 != nTemp)
1365 {
1366 nSeconds = nTemp;
1367 nTemp = -1;
1368 }
1369 else
1370 {
1371 bSuccess = false;
1372 }
1373 }
1374 }
1375 }
1376
1377 if (nPos != string.size()) // string not processed completely?
1378 {
1379 bSuccess = false;
1380 }
1381
1382 if (nTemp != -1) // unprocessed number?
1383 {
1384 bSuccess = false;
1385 }
1386
1387 if (bSuccess)
1388 {
1389 rDuration.Negative = bIsNegativeDuration;
1390 rDuration.Years = static_cast<sal_Int16>(nYears);
1391 rDuration.Months = static_cast<sal_Int16>(nMonths);
1392 rDuration.Days = static_cast<sal_Int16>(nDays);
1393 rDuration.Hours = static_cast<sal_Int16>(nHours);
1394 rDuration.Minutes = static_cast<sal_Int16>(nMinutes);
1395 rDuration.Seconds = static_cast<sal_Int16>(nSeconds);
1396 rDuration.NanoSeconds = nNanoSeconds;
1397 }
1398
1399 return bSuccess;
1400}
1401
1403bool Converter::convertDuration(util::Duration& rDuration,
1404 std::u16string_view rString)
1405{
1406 return convertDurationHelper(rDuration, o3tl::trim(rString));
1407}
1408
1410bool Converter::convertDuration(util::Duration& rDuration,
1411 std::string_view rString)
1412{
1413 return convertDurationHelper(rDuration, o3tl::trim(rString));
1414}
1415
1416static void
1417lcl_AppendTimezone(OUStringBuffer & i_rBuffer, int const nOffset)
1418{
1419 if (0 == nOffset)
1420 {
1421 i_rBuffer.append('Z');
1422 }
1423 else
1424 {
1425 if (0 < nOffset)
1426 {
1427 i_rBuffer.append('+');
1428 }
1429 else
1430 {
1431 i_rBuffer.append('-');
1432 }
1433 const sal_Int32 nHours (abs(nOffset) / 60);
1434 const sal_Int32 nMinutes(abs(nOffset) % 60);
1435 SAL_WARN_IF(nHours > 14 || (nHours == 14 && nMinutes > 0),
1436 "sax", "convertDateTime: timezone overflow");
1437 if (nHours < 10)
1438 {
1439 i_rBuffer.append('0');
1440 }
1441 i_rBuffer.append(nHours);
1442 i_rBuffer.append(':');
1443 if (nMinutes < 10)
1444 {
1445 i_rBuffer.append('0');
1446 }
1447 i_rBuffer.append(nMinutes);
1448 }
1449}
1450
1453 OUStringBuffer& i_rBuffer,
1454 const util::Date& i_rDate,
1455 sal_Int16 const*const pTimeZoneOffset)
1456{
1457 const util::DateTime dt(0, 0, 0, 0,
1458 i_rDate.Day, i_rDate.Month, i_rDate.Year, false);
1459 convertDateTime(i_rBuffer, dt, pTimeZoneOffset);
1460}
1461
1462static void convertTime(
1463 OUStringBuffer& i_rBuffer,
1464 const css::util::DateTime& i_rDateTime)
1465{
1466 if (i_rDateTime.Hours < 10) {
1467 i_rBuffer.append('0');
1468 }
1469 i_rBuffer.append( OUString::number(static_cast<sal_Int32>(i_rDateTime.Hours)) + ":");
1470 if (i_rDateTime.Minutes < 10) {
1471 i_rBuffer.append('0');
1472 }
1473 i_rBuffer.append( OUString::number(static_cast<sal_Int32>(i_rDateTime.Minutes) ) + ":");
1474 if (i_rDateTime.Seconds < 10) {
1475 i_rBuffer.append('0');
1476 }
1477 i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Seconds) );
1478 if (i_rDateTime.NanoSeconds > 0) {
1479 OSL_ENSURE(i_rDateTime.NanoSeconds < 1000000000,"NanoSeconds cannot be more than 999 999 999");
1480 i_rBuffer.append('.');
1481 std::ostringstream ostr;
1482 ostr.fill('0');
1483 ostr.width(9);
1484 ostr << i_rDateTime.NanoSeconds;
1485 i_rBuffer.appendAscii(ostr.str().c_str());
1486 }
1487}
1488
1490 OUStringBuffer& i_rBuffer,
1491 const css::util::DateTime& i_rDateTime,
1492 sal_Int16 const* pTimeZoneOffset)
1493{
1494 if (pTimeZoneOffset)
1495 {
1496 lcl_AppendTimezone(i_rBuffer, *pTimeZoneOffset);
1497 }
1498 else if (i_rDateTime.IsUTC)
1499 {
1500 lcl_AppendTimezone(i_rBuffer, 0);
1501 }
1502}
1503
1506 OUStringBuffer& i_rBuffer,
1507 const css::util::DateTime& i_rDateTime)
1508{
1509 if (i_rDateTime.Year == 0 ||
1510 i_rDateTime.Month < 1 || i_rDateTime.Month > 12 ||
1511 i_rDateTime.Day < 1 || i_rDateTime.Day > 31)
1512 {
1513 convertTime(i_rBuffer, i_rDateTime);
1514 convertTimeZone(i_rBuffer, i_rDateTime, nullptr);
1515 }
1516 else
1517 {
1518 convertDateTime(i_rBuffer, i_rDateTime, nullptr, true);
1519 }
1520}
1521
1524 OUStringBuffer& i_rBuffer,
1525 const css::util::DateTime& i_rDateTime,
1526 sal_Int16 const*const pTimeZoneOffset,
1527 bool i_bAddTimeIf0AM )
1528{
1529 const sal_Unicode dash('-');
1530 const sal_Unicode zero('0');
1531
1532 sal_Int32 const nYear(abs(i_rDateTime.Year));
1533 if (i_rDateTime.Year < 0) {
1534 i_rBuffer.append(dash); // negative
1535 }
1536 if (nYear < 1000) {
1537 i_rBuffer.append(zero);
1538 }
1539 if (nYear < 100) {
1540 i_rBuffer.append(zero);
1541 }
1542 if (nYear < 10) {
1543 i_rBuffer.append(zero);
1544 }
1545 i_rBuffer.append( OUString::number(nYear) + OUStringChar(dash) );
1546 if( i_rDateTime.Month < 10 ) {
1547 i_rBuffer.append(zero);
1548 }
1549 i_rBuffer.append( OUString::number(i_rDateTime.Month) + OUStringChar(dash) );
1550 if( i_rDateTime.Day < 10 ) {
1551 i_rBuffer.append(zero);
1552 }
1553 i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Day) );
1554
1555 if( i_rDateTime.Seconds != 0 ||
1556 i_rDateTime.Minutes != 0 ||
1557 i_rDateTime.Hours != 0 ||
1558 i_bAddTimeIf0AM )
1559 {
1560 i_rBuffer.append('T');
1561 convertTime(i_rBuffer, i_rDateTime);
1562 }
1563
1564 convertTimeZone(i_rBuffer, i_rDateTime, pTimeZoneOffset);
1565}
1566
1568bool Converter::parseDateTime( util::DateTime& rDateTime,
1569 std::u16string_view rString )
1570{
1571 bool isDateTime;
1572 return parseDateOrDateTime(nullptr, rDateTime, isDateTime, nullptr,
1573 rString);
1574}
1575
1577bool Converter::parseDateTime( util::DateTime& rDateTime,
1578 std::string_view rString )
1579{
1580 bool isDateTime;
1581 return parseDateOrDateTime(nullptr, rDateTime, isDateTime, nullptr,
1582 rString);
1583}
1584
1585static bool lcl_isLeapYear(const sal_uInt32 nYear)
1586{
1587 return ((nYear % 4) == 0)
1588 && (((nYear % 100) != 0) || ((nYear % 400) == 0));
1589}
1590
1591static sal_uInt16
1592lcl_MaxDaysPerMonth(const sal_Int32 nMonth, const sal_Int32 nYear)
1593{
1594 static const sal_uInt16 s_MaxDaysPerMonth[12] =
1595 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1596 assert(0 < nMonth && nMonth <= 12);
1597 if ((2 == nMonth) && lcl_isLeapYear(nYear))
1598 {
1599 return 29;
1600 }
1601 return s_MaxDaysPerMonth[nMonth - 1];
1602}
1603
1605 sal_Int16 & o_rYear, sal_uInt16 & o_rMonth, sal_uInt16 & o_rDay,
1606 sal_uInt16 & o_rHours, sal_uInt16 & o_rMinutes,
1607 int const nSourceOffset)
1608{
1609 sal_Int16 nOffsetHours(abs(nSourceOffset) / 60);
1610 sal_Int16 const nOffsetMinutes(abs(nSourceOffset) % 60);
1611 o_rMinutes += nOffsetMinutes;
1612 if (nSourceOffset < 0)
1613 {
1614 o_rMinutes += nOffsetMinutes;
1615 if (60 <= o_rMinutes)
1616 {
1617 o_rMinutes -= 60;
1618 ++nOffsetHours;
1619 }
1620 o_rHours += nOffsetHours;
1621 if (o_rHours < 24)
1622 {
1623 return;
1624 }
1625 sal_Int16 nDayAdd(0);
1626 while (24 <= o_rHours)
1627 {
1628 o_rHours -= 24;
1629 ++nDayAdd;
1630 }
1631 if (o_rDay == 0)
1632 {
1633 return; // handle time without date - don't adjust what isn't there
1634 }
1635 o_rDay += nDayAdd;
1636 sal_Int16 const nDaysInMonth(lcl_MaxDaysPerMonth(o_rMonth, o_rYear));
1637 if (o_rDay <= nDaysInMonth)
1638 {
1639 return;
1640 }
1641 o_rDay -= nDaysInMonth;
1642 ++o_rMonth;
1643 if (o_rMonth <= 12)
1644 {
1645 return;
1646 }
1647 o_rMonth = 1;
1648 ++o_rYear; // works for negative year too
1649 }
1650 else if (0 < nSourceOffset)
1651 {
1652 // argh everything is unsigned
1653 if (o_rMinutes < nOffsetMinutes)
1654 {
1655 o_rMinutes += 60;
1656 ++nOffsetHours;
1657 }
1658 o_rMinutes -= nOffsetMinutes;
1659 sal_Int16 nDaySubtract(0);
1660 while (o_rHours < nOffsetHours)
1661 {
1662 o_rHours += 24;
1663 ++nDaySubtract;
1664 }
1665 o_rHours -= nOffsetHours;
1666 if (o_rDay == 0)
1667 {
1668 return; // handle time without date - don't adjust what isn't there
1669 }
1670 if (nDaySubtract < o_rDay)
1671 {
1672 o_rDay -= nDaySubtract;
1673 return;
1674 }
1675 sal_Int16 const nPrevMonth((o_rMonth == 1) ? 12 : o_rMonth - 1);
1676 sal_Int16 const nDaysInMonth(lcl_MaxDaysPerMonth(nPrevMonth, o_rYear));
1677 o_rDay += nDaysInMonth;
1678 --o_rMonth;
1679 if (0 == o_rMonth)
1680 {
1681 o_rMonth = 12;
1682 --o_rYear; // works for negative year too
1683 }
1684 o_rDay -= nDaySubtract;
1685 }
1686}
1687
1688template <typename V>
1689static bool
1691 size_t & io_rnPos, sal_Int32 & o_rnTarget,
1692 const sal_Int32 nMinLength, const bool bExactLength)
1693{
1694 const size_t nOldPos(io_rnPos);
1695 sal_Int32 nTemp(0);
1696 if (R_SUCCESS != readUnsignedNumber<V>(rString, io_rnPos, nTemp))
1697 {
1698 return false;
1699 }
1700 const sal_Int32 nTokenLength(io_rnPos - nOldPos);
1701 if ((nTokenLength < nMinLength) ||
1702 (bExactLength && (nTokenLength > nMinLength)))
1703 {
1704 return false; // bad length
1705 }
1706 o_rnTarget = nTemp;
1707 return true;
1708}
1709
1711template<typename V>
1712static bool lcl_parseDate(
1713 bool & isNegative,
1714 sal_Int32 & nYear, sal_Int32 & nMonth, sal_Int32 & nDay,
1715 bool & bHaveTime,
1716 size_t & nPos,
1717 V string,
1718 bool const bIgnoreInvalidOrMissingDate)
1719{
1720 bool bSuccess = true;
1721
1722 if (string.size() > nPos)
1723 {
1724 if ('-' == string[nPos])
1725 {
1726 isNegative = true;
1727 ++nPos;
1728 }
1729 }
1730
1731 {
1732 // While W3C XMLSchema specifies years with a minimum of 4 digits, be
1733 // lenient in what we accept for years < 1000. One digit is acceptable
1734 // if the remainders match.
1735 bSuccess = readDateTimeComponent<V>(string, nPos, nYear, 1, false);
1736 if (!bIgnoreInvalidOrMissingDate)
1737 {
1738 bSuccess &= (0 < nYear);
1739 }
1740 bSuccess &= (nPos < string.size()); // not last token
1741 }
1742 if (bSuccess && ('-' != string[nPos])) // separator
1743 {
1744 bSuccess = false;
1745 }
1746 if (bSuccess)
1747 {
1748 ++nPos;
1749
1750 bSuccess = readDateTimeComponent<V>(string, nPos, nMonth, 2, true);
1751 if (!bIgnoreInvalidOrMissingDate)
1752 {
1753 bSuccess &= (0 < nMonth);
1754 }
1755 bSuccess &= (nMonth <= 12);
1756 bSuccess &= (nPos < string.size()); // not last token
1757 }
1758 if (bSuccess && ('-' != string[nPos])) // separator
1759 {
1760 bSuccess = false;
1761 }
1762 if (bSuccess)
1763 {
1764 ++nPos;
1765
1766 bSuccess = readDateTimeComponent(string, nPos, nDay, 2, true);
1767 if (!bIgnoreInvalidOrMissingDate)
1768 {
1769 bSuccess &= (0 < nDay);
1770 }
1771 if (nMonth > 0) // not possible to check if month was missing
1772 {
1773 bSuccess &= (nDay <= lcl_MaxDaysPerMonth(nMonth, nYear));
1774 }
1775 else assert(bIgnoreInvalidOrMissingDate);
1776 }
1777
1778 if (bSuccess && (nPos < string.size()))
1779 {
1780 if ('T' == string[nPos] || 't' == string[nPos]) // time separator
1781 {
1782 bHaveTime = true;
1783 ++nPos;
1784 }
1785 }
1786
1787 return bSuccess;
1788}
1789
1791template <typename V>
1793 util::Date *const pDate, util::DateTime & rDateTime,
1794 bool & rbDateTime,
1795 std::optional<sal_Int16> *const pTimeZoneOffset,
1796 V string,
1797 bool const bIgnoreInvalidOrMissingDate)
1798{
1799 bool bSuccess = true;
1800
1801 string = o3tl::trim(string);
1802
1803 bool isNegative(false);
1804 sal_Int32 nYear(0);
1805 sal_Int32 nMonth(0);
1806 sal_Int32 nDay(0);
1807 size_t nPos(0);
1808 bool bHaveTime(false);
1809
1810 if ( !bIgnoreInvalidOrMissingDate
1811 || string.find(':') == V::npos // no time?
1812 || (string.find('-') != V::npos
1813 && string.find('-') < string.find(':')))
1814 {
1815 bSuccess &= lcl_parseDate<V>(isNegative, nYear, nMonth, nDay,
1816 bHaveTime, nPos, string, bIgnoreInvalidOrMissingDate);
1817 }
1818 else
1819 {
1820 bHaveTime = true;
1821 }
1822
1823 sal_Int32 nHours(0);
1824 sal_Int32 nMinutes(0);
1825 sal_Int32 nSeconds(0);
1826 sal_Int32 nNanoSeconds(0);
1827 if (bSuccess && bHaveTime)
1828 {
1829 {
1830 bSuccess = readDateTimeComponent(string, nPos, nHours, 2, true);
1831 bSuccess &= (0 <= nHours) && (nHours <= 24);
1832 bSuccess &= (nPos < string.size()); // not last token
1833 }
1834 if (bSuccess && (':' != string[nPos])) // separator
1835 {
1836 bSuccess = false;
1837 }
1838 if (bSuccess)
1839 {
1840 ++nPos;
1841
1842 bSuccess = readDateTimeComponent(string, nPos, nMinutes, 2, true);
1843 bSuccess &= (0 <= nMinutes) && (nMinutes < 60);
1844 bSuccess &= (nPos < string.size()); // not last token
1845 }
1846 if (bSuccess && (':' != string[nPos])) // separator
1847 {
1848 bSuccess = false;
1849 }
1850 if (bSuccess)
1851 {
1852 ++nPos;
1853
1854 bSuccess = readDateTimeComponent(string, nPos, nSeconds, 2, true);
1855 bSuccess &= (0 <= nSeconds) && (nSeconds < 60);
1856 }
1857 if (bSuccess && (nPos < string.size()) &&
1858 ('.' == string[nPos] || ',' == string[nPos])) // fraction separator
1859 {
1860 ++nPos;
1861 const sal_Int32 nStart(nPos);
1862 sal_Int32 nTemp(0);
1863 if (R_NOTHING == readUnsignedNumberMaxDigits<V>(9, string, nPos, nTemp))
1864 {
1865 bSuccess = false;
1866 }
1867 if (bSuccess)
1868 {
1869 sal_Int32 nDigits = std::min<sal_Int32>(nPos - nStart, 9);
1870 assert(nDigits > 0);
1871 for (; nDigits < 9; ++nDigits)
1872 {
1873 nTemp *= 10;
1874 }
1875 nNanoSeconds = nTemp;
1876 }
1877 }
1878
1879 if (bSuccess && (nHours == 24))
1880 {
1881 if (!((0 == nMinutes) && (0 == nSeconds) && (0 == nNanoSeconds)))
1882 {
1883 bSuccess = false; // only 24:00:00 is valid
1884 }
1885 }
1886 }
1887
1888 bool bHaveTimezone(false);
1889 bool bHaveTimezonePlus(false);
1890 bool bHaveTimezoneMinus(false);
1891 if (bSuccess && (nPos < string.size()))
1892 {
1893 const sal_Unicode c(string[nPos]);
1894 if ('+' == c)
1895 {
1896 bHaveTimezone = true;
1897 bHaveTimezonePlus = true;
1898 ++nPos;
1899 }
1900 else if ('-' == c)
1901 {
1902 bHaveTimezone = true;
1903 bHaveTimezoneMinus = true;
1904 ++nPos;
1905 }
1906 else if ('Z' == c || 'z' == c)
1907 {
1908 bHaveTimezone = true;
1909 ++nPos;
1910 }
1911 else
1912 {
1913 bSuccess = false;
1914 }
1915 }
1916 sal_Int32 nTimezoneHours(0);
1917 sal_Int32 nTimezoneMinutes(0);
1918 if (bSuccess && (bHaveTimezonePlus || bHaveTimezoneMinus))
1919 {
1920 bSuccess = readDateTimeComponent<V>(
1921 string, nPos, nTimezoneHours, 2, true);
1922 bSuccess &= (0 <= nTimezoneHours) && (nTimezoneHours <= 14);
1923 bSuccess &= (nPos < string.size()); // not last token
1924 if (bSuccess && (':' != string[nPos])) // separator
1925 {
1926 bSuccess = false;
1927 }
1928 if (bSuccess)
1929 {
1930 ++nPos;
1931
1932 bSuccess = readDateTimeComponent<V>(
1933 string, nPos, nTimezoneMinutes, 2, true);
1934 bSuccess &= (0 <= nTimezoneMinutes) && (nTimezoneMinutes < 60);
1935 }
1936 if (bSuccess && (nTimezoneHours == 14))
1937 {
1938 if (0 != nTimezoneMinutes)
1939 {
1940 bSuccess = false; // only +-14:00 is valid
1941 }
1942 }
1943 }
1944
1945 bSuccess &= (nPos == string.size()); // trailing junk?
1946
1947 if (bSuccess)
1948 {
1949 sal_Int16 const nTimezoneOffset = (bHaveTimezoneMinus ? -1 : +1)
1950 * ((nTimezoneHours * 60) + nTimezoneMinutes);
1951 if (!pDate || bHaveTime) // time is optional
1952 {
1953 rDateTime.Year =
1954 (isNegative ? -1 : +1) * static_cast<sal_Int16>(nYear);
1955 rDateTime.Month = static_cast<sal_uInt16>(nMonth);
1956 rDateTime.Day = static_cast<sal_uInt16>(nDay);
1957 rDateTime.Hours = static_cast<sal_uInt16>(nHours);
1958 rDateTime.Minutes = static_cast<sal_uInt16>(nMinutes);
1959 rDateTime.Seconds = static_cast<sal_uInt16>(nSeconds);
1960 rDateTime.NanoSeconds = static_cast<sal_uInt32>(nNanoSeconds);
1961 if (bHaveTimezone)
1962 {
1963 if (pTimeZoneOffset)
1964 {
1965 *pTimeZoneOffset = nTimezoneOffset;
1966 rDateTime.IsUTC = (0 == nTimezoneOffset);
1967 }
1968 else
1969 {
1970 lcl_ConvertToUTC(rDateTime.Year, rDateTime.Month,
1971 rDateTime.Day, rDateTime.Hours, rDateTime.Minutes,
1972 nTimezoneOffset);
1973 rDateTime.IsUTC = true;
1974 }
1975 }
1976 else
1977 {
1978 if (pTimeZoneOffset)
1979 {
1980 pTimeZoneOffset->reset();
1981 }
1982 rDateTime.IsUTC = false;
1983 }
1984 rbDateTime = bHaveTime;
1985 }
1986 else
1987 {
1988 pDate->Year =
1989 (isNegative ? -1 : +1) * static_cast<sal_Int16>(nYear);
1990 pDate->Month = static_cast<sal_uInt16>(nMonth);
1991 pDate->Day = static_cast<sal_uInt16>(nDay);
1992 if (bHaveTimezone)
1993 {
1994 if (pTimeZoneOffset)
1995 {
1996 *pTimeZoneOffset = nTimezoneOffset;
1997 }
1998 else
1999 {
2000 // a Date cannot be adjusted
2001 SAL_INFO("sax", "dropping timezone");
2002 }
2003 }
2004 else
2005 {
2006 if (pTimeZoneOffset)
2007 {
2008 pTimeZoneOffset->reset();
2009 }
2010 }
2011 rbDateTime = false;
2012 }
2013 }
2014 return bSuccess;
2015}
2016
2019 util::DateTime & rDateTime,
2020 std::u16string_view rString)
2021{
2022 bool dummy;
2023 return lcl_parseDateTime(
2024 nullptr, rDateTime, dummy, nullptr, rString, true);
2025}
2026
2029 util::DateTime & rDateTime,
2030 std::string_view rString)
2031{
2032 bool dummy;
2033 return lcl_parseDateTime(
2034 nullptr, rDateTime, dummy, nullptr, rString, true);
2035}
2036
2039 util::Date *const pDate, util::DateTime & rDateTime,
2040 bool & rbDateTime,
2041 std::optional<sal_Int16> *const pTimeZoneOffset,
2042 std::u16string_view rString )
2043{
2044 return lcl_parseDateTime(
2045 pDate, rDateTime, rbDateTime, pTimeZoneOffset, rString, false);
2046}
2047
2050 util::Date *const pDate, util::DateTime & rDateTime,
2051 bool & rbDateTime,
2052 std::optional<sal_Int16> *const pTimeZoneOffset,
2053 std::string_view rString )
2054{
2055 return lcl_parseDateTime(
2056 pDate, rDateTime, rbDateTime, pTimeZoneOffset, rString, false);
2057}
2058
2061sal_Int32 Converter::indexOfComma( std::u16string_view rStr,
2062 sal_Int32 nPos )
2063{
2064 sal_Unicode cQuote = 0;
2065 sal_Int32 nLen = rStr.size();
2066 for( ; nPos < nLen; nPos++ )
2067 {
2068 sal_Unicode c = rStr[nPos];
2069 switch( c )
2070 {
2071 case u'\'':
2072 if( 0 == cQuote )
2073 cQuote = c;
2074 else if( '\'' == cQuote )
2075 cQuote = 0;
2076 break;
2077
2078 case u'"':
2079 if( 0 == cQuote )
2080 cQuote = c;
2081 else if( '\"' == cQuote )
2082 cQuote = 0;
2083 break;
2084
2085 case u',':
2086 if( 0 == cQuote )
2087 return nPos;
2088 break;
2089 }
2090 }
2091
2092 return -1;
2093}
2094
2095double Converter::GetConversionFactor(OUStringBuffer& rUnit, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
2096{
2097 double fRetval(1.0);
2098 rUnit.setLength(0);
2099
2100
2101 if(nSourceUnit != nTargetUnit)
2102 {
2103 const o3tl::Length eFrom = Measure2O3tlUnit(nSourceUnit);
2104 const o3tl::Length eTo = Measure2O3tlUnit(nTargetUnit);
2105 fRetval = o3tl::convert(1.0, eFrom, eTo);
2106
2107 if (const auto sUnit = Measure2UnitString(nTargetUnit); sUnit.size() > 0)
2108 rUnit.appendAscii(sUnit.data(), sUnit.size());
2109 }
2110
2111 return fRetval;
2112}
2113
2114double Converter::GetConversionFactor(OStringBuffer& rUnit, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
2115{
2116 double fRetval(1.0);
2117 rUnit.setLength(0);
2118
2119
2120 if(nSourceUnit != nTargetUnit)
2121 {
2122 const o3tl::Length eFrom = Measure2O3tlUnit(nSourceUnit);
2123 const o3tl::Length eTo = Measure2O3tlUnit(nTargetUnit);
2124 fRetval = o3tl::convert(1.0, eFrom, eTo);
2125
2126 if (const auto sUnit = Measure2UnitString(nTargetUnit); sUnit.size() > 0)
2127 rUnit.append(sUnit.data(), sUnit.size());
2128 }
2129
2130 return fRetval;
2131}
2132
2133template<typename V>
2134static sal_Int16 lcl_GetUnitFromString(V rString, sal_Int16 nDefaultUnit)
2135{
2136 sal_Int32 nPos = 0;
2137 sal_Int32 nLen = rString.size();
2138 sal_Int16 nRetUnit = nDefaultUnit;
2139
2140 // skip white space
2141 while( nPos < nLen && ' ' == rString[nPos] )
2142 nPos++;
2143
2144 // skip negative
2145 if( nPos < nLen && '-' == rString[nPos] )
2146 nPos++;
2147
2148 // skip number
2149 while( nPos < nLen && '0' <= rString[nPos] && '9' >= rString[nPos] )
2150 nPos++;
2151
2152 if( nPos < nLen && '.' == rString[nPos] )
2153 {
2154 nPos++;
2155 while( nPos < nLen && '0' <= rString[nPos] && '9' >= rString[nPos] )
2156 nPos++;
2157 }
2158
2159 // skip white space
2160 while( nPos < nLen && ' ' == rString[nPos] )
2161 nPos++;
2162
2163 if( nPos < nLen )
2164 {
2165 switch(rString[nPos])
2166 {
2167 case '%' :
2168 {
2169 nRetUnit = MeasureUnit::PERCENT;
2170 break;
2171 }
2172 case 'c':
2173 case 'C':
2174 {
2175 if(nPos+1 < nLen && (rString[nPos+1] == 'm'
2176 || rString[nPos+1] == 'M'))
2177 nRetUnit = MeasureUnit::CM;
2178 break;
2179 }
2180 case 'e':
2181 case 'E':
2182 {
2183 // CSS1_EMS or CSS1_EMX later
2184 break;
2185 }
2186 case 'i':
2187 case 'I':
2188 {
2189 if(nPos+1 < nLen && (rString[nPos+1] == 'n'
2190 || rString[nPos+1] == 'N'))
2191 nRetUnit = MeasureUnit::INCH;
2192 break;
2193 }
2194 case 'm':
2195 case 'M':
2196 {
2197 if(nPos+1 < nLen && (rString[nPos+1] == 'm'
2198 || rString[nPos+1] == 'M'))
2199 nRetUnit = MeasureUnit::MM;
2200 break;
2201 }
2202 case 'p':
2203 case 'P':
2204 {
2205 if(nPos+1 < nLen && (rString[nPos+1] == 't'
2206 || rString[nPos+1] == 'T'))
2207 nRetUnit = MeasureUnit::POINT;
2208 if(nPos+1 < nLen && (rString[nPos+1] == 'c'
2209 || rString[nPos+1] == 'C'))
2210 nRetUnit = MeasureUnit::TWIP;
2211 break;
2212 }
2213 }
2214 }
2215
2216 return nRetUnit;
2217}
2218
2219sal_Int16 Converter::GetUnitFromString(std::u16string_view rString, sal_Int16 nDefaultUnit)
2220{
2221 return lcl_GetUnitFromString(rString, nDefaultUnit);
2222}
2223sal_Int16 Converter::GetUnitFromString(std::string_view rString, sal_Int16 nDefaultUnit)
2224{
2225 return lcl_GetUnitFromString(rString, nDefaultUnit);
2226}
2227
2228bool Converter::convertAny(OUStringBuffer& rsValue,
2229 OUStringBuffer& rsType ,
2230 const css::uno::Any& rValue)
2231{
2232 bool bConverted = false;
2233
2234 rsValue.setLength(0);
2235 rsType.setLength (0);
2236
2237 switch (rValue.getValueTypeClass())
2238 {
2239 case css::uno::TypeClass_BYTE :
2240 case css::uno::TypeClass_SHORT :
2241 case css::uno::TypeClass_UNSIGNED_SHORT :
2242 case css::uno::TypeClass_LONG :
2243 case css::uno::TypeClass_UNSIGNED_LONG :
2244 {
2245 sal_Int32 nTempValue = 0;
2246 if (rValue >>= nTempValue)
2247 {
2248 rsType.append("integer");
2249 bConverted = true;
2250 rsValue.append(nTempValue);
2251 }
2252 }
2253 break;
2254
2255 case css::uno::TypeClass_BOOLEAN :
2256 {
2257 bool bTempValue = false;
2258 if (rValue >>= bTempValue)
2259 {
2260 rsType.append("boolean");
2261 bConverted = true;
2262 ::sax::Converter::convertBool(rsValue, bTempValue);
2263 }
2264 }
2265 break;
2266
2267 case css::uno::TypeClass_FLOAT :
2268 case css::uno::TypeClass_DOUBLE :
2269 {
2270 double fTempValue = 0.0;
2271 if (rValue >>= fTempValue)
2272 {
2273 rsType.append("float");
2274 bConverted = true;
2275 ::sax::Converter::convertDouble(rsValue, fTempValue);
2276 }
2277 }
2278 break;
2279
2280 case css::uno::TypeClass_STRING :
2281 {
2282 OUString sTempValue;
2283 if (rValue >>= sTempValue)
2284 {
2285 rsType.append("string");
2286 bConverted = true;
2287 rsValue.append(sTempValue);
2288 }
2289 }
2290 break;
2291
2292 case css::uno::TypeClass_STRUCT :
2293 {
2294 css::util::Date aDate ;
2295 css::util::Time aTime ;
2296 css::util::DateTime aDateTime;
2297
2298 if (rValue >>= aDate)
2299 {
2300 rsType.append("date");
2301 bConverted = true;
2302 css::util::DateTime aTempValue;
2303 aTempValue.Day = aDate.Day;
2304 aTempValue.Month = aDate.Month;
2305 aTempValue.Year = aDate.Year;
2306 aTempValue.NanoSeconds = 0;
2307 aTempValue.Seconds = 0;
2308 aTempValue.Minutes = 0;
2309 aTempValue.Hours = 0;
2310 ::sax::Converter::convertDateTime(rsValue, aTempValue, nullptr);
2311 }
2312 else
2313 if (rValue >>= aTime)
2314 {
2315 rsType.append("time");
2316 bConverted = true;
2317 css::util::Duration aTempValue;
2318 aTempValue.Days = 0;
2319 aTempValue.Months = 0;
2320 aTempValue.Years = 0;
2321 aTempValue.NanoSeconds = aTime.NanoSeconds;
2322 aTempValue.Seconds = aTime.Seconds;
2323 aTempValue.Minutes = aTime.Minutes;
2324 aTempValue.Hours = aTime.Hours;
2325 ::sax::Converter::convertDuration(rsValue, aTempValue);
2326 }
2327 else
2328 if (rValue >>= aDateTime)
2329 {
2330 rsType.append("date");
2331 bConverted = true;
2332 ::sax::Converter::convertDateTime(rsValue, aDateTime, nullptr);
2333 }
2334 }
2335 break;
2336 default:
2337 break;
2338 }
2339
2340 return bConverted;
2341}
2342
2343void Converter::convertBytesToHexBinary(OUStringBuffer& rBuffer, const void* pBytes,
2344 sal_Int32 nBytes)
2345{
2346 rBuffer.setLength(0);
2347 rBuffer.ensureCapacity(nBytes * 2);
2348 auto pChars = static_cast<const unsigned char*>(pBytes);
2349 for (sal_Int32 i = 0; i < nBytes; ++i)
2350 {
2351 sal_Int32 c = *pChars++;
2352 if (c < 16)
2353 rBuffer.append('0');
2354 rBuffer.append(c, 16);
2355 }
2356}
2357
2358}
2359
2360/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static bool parseTimeOrDateTime(css::util::DateTime &rDateTime, std::u16string_view rString)
convert XMLSchema-2 "time" or "dateTime" string to util::DateTime
static void convertDateTime(OUStringBuffer &rBuffer, const css::util::DateTime &rDateTime, sal_Int16 const *pTimeZoneOffset, bool bAddTimeIf0AM=false)
convert util::DateTime to XMLSchema-2 "date" or "dateTime" string
Definition: converter.cxx:1523
static void convertDouble(OUStringBuffer &rBuffer, double fNumber, bool bWriteUnits, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
convert double number to string (using ::rtl::math) and DO convert from source unit to target unit
Definition: converter.cxx:643
static bool convertMeasure(sal_Int32 &rValue, std::u16string_view rString, sal_Int16 nTargetUnit=css::util::MeasureUnit::MM_100TH, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32)
convert string to measure using optional min and max values
Definition: converter.cxx:282
static bool convertMeasurePx(sal_Int32 &rValue, std::u16string_view rString)
convert string to pixel measure unit
Definition: converter.cxx:480
static bool convertPercent(sal_Int32 &rValue, std::u16string_view rString)
convert string to percent
Definition: converter.cxx:461
static bool convertColor(sal_Int32 &rColor, std::u16string_view rValue)
convert string to rgb color
Definition: converter.cxx:530
static void convertDuration(OUStringBuffer &rBuffer, const double fTime)
convert double to XMLSchema-2 "duration" string; negative durations allowed
Definition: converter.cxx:846
static void convertTimeOrDateTime(OUStringBuffer &rBuffer, const css::util::DateTime &rDateTime)
convert util::DateTime to XMLSchema-2 "time" or "dateTime" string
Definition: converter.cxx:1505
static double GetConversionFactor(OUStringBuffer &rUnit, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
Definition: converter.cxx:2095
static bool parseDateTime(css::util::DateTime &rDateTime, std::u16string_view rString)
convert XMLSchema-2 "date" or "dateTime" string to util::DateTime
static void convertBytesToHexBinary(OUStringBuffer &rBuffer, const void *pBytes, sal_Int32 nBytes)
convert specified byte sequence to xsd:hexBinary string
Definition: converter.cxx:2343
static sal_Int16 GetUnitFromString(std::u16string_view rString, sal_Int16 nDefaultUnit)
Definition: converter.cxx:2219
static bool convertNumber64(sal_Int64 &rValue, std::u16string_view aString, sal_Int64 nMin=SAL_MIN_INT64, sal_Int64 nMax=SAL_MAX_INT64)
convert string to number with optional min and max values
Definition: converter.cxx:626
static bool parseDateOrDateTime(css::util::Date *pDate, css::util::DateTime &rDateTime, bool &rbDateTime, std::optional< sal_Int16 > *pTimeZoneOffset, std::u16string_view rString)
convert XMLSchema-2 "date" or "dateTime" string to util::DateTime or util::Date
static void convertAngle(OUStringBuffer &rBuffer, sal_Int16 nAngle, SvtSaveOptions::ODFSaneDefaultVersion nVersion)
convert number, 10th of degrees with range [0..3600] to SVG angle
Definition: converter.cxx:729
static void convertDate(OUStringBuffer &rBuffer, const css::util::Date &rDate, sal_Int16 const *pTimeZoneOffset)
convert util::Date to XMLSchema-2 "date" string
Definition: converter.cxx:1452
static bool convertNumber(sal_Int32 &rValue, std::u16string_view aString, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32)
convert string to number with optional min and max values
Definition: converter.cxx:562
static sal_Int32 indexOfComma(std::u16string_view rStr, sal_Int32 nPos)
gets the position of the first comma after npos in the string rStr.
Definition: converter.cxx:2061
static bool convertBool(bool &rBool, std::u16string_view rString)
convert string to boolean
Definition: converter.cxx:439
static bool convertAny(OUStringBuffer &rsValue, OUStringBuffer &rsType, const css::uno::Any &rValue)
convert an Any to string (typesafe)
Definition: converter.cxx:2228
float u
sal_Int16 nVersion
sal_Int16 nValue
sal_uInt16 nPos
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
size
OSQLColumns::const_iterator find(const OSQLColumns::const_iterator &first, const OSQLColumns::const_iterator &last, std::u16string_view _rVal, const ::comphelper::UStringMixEqual &_rCase)
int i
std::basic_string_view< charT, traits > trim(std::basic_string_view< charT, traits > str)
constexpr Point convert(const Point &rPoint, o3tl::Length eFrom, o3tl::Length eTo)
double toDouble(std::u16string_view str)
static bool lcl_parseDate(bool &isNegative, sal_Int32 &nYear, sal_Int32 &nMonth, sal_Int32 &nDay, bool &bHaveTime, size_t &nPos, V string, bool const bIgnoreInvalidOrMissingDate)
convert ISO "date" or "dateTime" string to util::DateTime or util::Date
Definition: converter.cxx:1712
static sal_uInt16 lcl_MaxDaysPerMonth(const sal_Int32 nMonth, const sal_Int32 nYear)
Definition: converter.cxx:1592
static bool lcl_isLeapYear(const sal_uInt32 nYear)
Definition: converter.cxx:1585
const std::string_view gpsINCH
Definition: converter.cxx:53
static Result readUnsignedNumber(V rString, size_t &io_rnPos, sal_Int32 &o_rNumber)
Definition: converter.cxx:1127
static int lcl_gethex(int nChar)
Definition: converter.cxx:499
static bool convertDurationHelper(double &rfTime, V pStr)
helper function of Converter::convertDuration
Definition: converter.cxx:918
static bool lcl_convertNumber64(sal_Int64 &rValue, V aString, sal_Int64 nMin, sal_Int64 nMax)
convert string to 64-bit number with optional min and max values
Definition: converter.cxx:589
static bool lcl_parseDateTime(util::Date *const pDate, util::DateTime &rDateTime, bool &rbDateTime, std::optional< sal_Int16 > *const pTimeZoneOffset, V string, bool const bIgnoreInvalidOrMissingDate)
convert ISO "date" or "dateTime" string to util::DateTime or util::Date
Definition: converter.cxx:1792
static sal_Int16 lcl_GetUnitFromString(V rString, sal_Int16 nDefaultUnit)
Definition: converter.cxx:2134
const char aHexTab[]
Definition: converter.cxx:541
static void convertTime(OUStringBuffer &i_rBuffer, const css::util::DateTime &i_rDateTime)
Definition: converter.cxx:1462
static sal_Int64 toInt64_WithLength(const sal_Unicode *str, sal_Int16 radix, sal_Int32 nStrLength)
Definition: converter.cxx:58
static void lcl_ConvertToUTC(sal_Int16 &o_rYear, sal_uInt16 &o_rMonth, sal_uInt16 &o_rDay, sal_uInt16 &o_rHours, sal_uInt16 &o_rMinutes, int const nSourceOffset)
Definition: converter.cxx:1604
static Result readUnsignedNumberMaxDigits(int maxDigits, V rString, size_t &io_rnPos, sal_Int32 &o_rNumber)
Definition: converter.cxx:1157
const std::string_view gpsMM
Definition: converter.cxx:50
const sal_Int8 XML_MAXDIGITSCOUNT_TIME
Definition: converter.cxx:56
static bool readDateTimeComponent(V rString, size_t &io_rnPos, sal_Int32 &o_rnTarget, const sal_Int32 nMinLength, const bool bExactLength)
Definition: converter.cxx:1690
const std::string_view gpsPT
Definition: converter.cxx:52
static void convertTimeZone(OUStringBuffer &i_rBuffer, const css::util::DateTime &i_rDateTime, sal_Int16 const *pTimeZoneOffset)
Definition: converter.cxx:1489
const std::string_view gpsPC
Definition: converter.cxx:54
static bool readDurationT(V rString, size_t &io_rnPos)
Definition: converter.cxx:1202
static bool readDurationComponent(V rString, size_t &io_rnPos, sal_Int32 &io_rnTemp, bool &io_rbTimePart, sal_Int32 &o_rnTarget, const sal_Unicode cLower, const sal_Unicode cUpper)
Definition: converter.cxx:1215
static void lcl_AppendTimezone(OUStringBuffer &i_rBuffer, int const nOffset)
Definition: converter.cxx:1417
const std::string_view gpsCM
Definition: converter.cxx:51
static bool lcl_convertColor(sal_Int32 &rColor, V rValue)
convert string to rgb color
Definition: converter.cxx:513
static bool lcl_convertMeasure(sal_Int32 &rValue, V rString, sal_Int16 nTargetUnit, sal_Int32 nMin, sal_Int32 nMax)
convert string to measure using optional min and max values
Definition: converter.cxx:126
SwNodeOffset abs(const SwNodeOffset &a)
unsigned char sal_uInt8
#define SAL_MAX_INT32
sal_uInt16 sal_Unicode
signed char sal_Int8
const sal_uInt8 V