LibreOffice Module xmloff (master) 1
xmluconv.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
20#include <sal/config.h>
21
22#include <string_view>
23
24#include <utility>
25#include <xmloff/xmluconv.hxx>
26
27#include <com/sun/star/util/DateTime.hpp>
28#include <com/sun/star/util/Date.hpp>
29#include <rtl/ustrbuf.hxx>
30#include <osl/diagnose.h>
31#include <sal/log.hxx>
32#include <xmloff/xmlement.hxx>
33#include <xmloff/xmltoken.hxx>
34#include <rtl/math.hxx>
35
36#include <tools/date.hxx>
37#include <tools/time.hxx>
38#include <tools/fldunit.hxx>
39
40#include <com/sun/star/drawing/Position3D.hpp>
41#include <com/sun/star/frame/XModel.hpp>
42#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
43#include <com/sun/star/style/NumberingType.hpp>
44#include <com/sun/star/text/DefaultNumberingProvider.hpp>
45#include <com/sun/star/text/XDefaultNumberingProvider.hpp>
46#include <com/sun/star/text/XNumberingTypeInfo.hpp>
47#include <com/sun/star/i18n/CharacterClassification.hpp>
48#include <com/sun/star/i18n/UnicodeType.hpp>
50
53
54
55using namespace com::sun::star;
56using namespace com::sun::star::uno;
57using namespace com::sun::star::lang;
58using namespace com::sun::star::text;
59using namespace com::sun::star::style;
60using namespace ::com::sun::star::i18n;
61using namespace ::xmloff::token;
62
63
65constexpr OUStringLiteral XML_NULLDATE = u"NullDate";
66
68{
69 sal_Int16 m_eCoreMeasureUnit; /*css::util::MeasureUnit*/
70 sal_Int16 m_eXMLMeasureUnit; /*css::util::MeasureUnit*/
72 util::Date m_aNullDate;
73 mutable uno::Reference< text::XNumberingTypeInfo > m_xNumTypeInfo;
74 mutable uno::Reference< i18n::XCharacterClassification > m_xCharClass;
75 uno::Reference< uno::XComponentContext > m_xContext;
76
77 Impl(uno::Reference<uno::XComponentContext> xContext,
78 sal_Int16 const eCoreMeasureUnit,
79 sal_Int16 const eXMLMeasureUnit,
81 : m_eCoreMeasureUnit(eCoreMeasureUnit)
82 , m_eXMLMeasureUnit(eXMLMeasureUnit)
83 , m_eODFVersion(nODFVersion)
84 , m_aNullDate(30, 12, 1899)
85 , m_xContext(std::move(xContext))
86 {
87 OSL_ENSURE( m_xContext.is(), "got no service manager" );
88 }
89
90 void createNumTypeInfo() const;
91};
92
93
95{
96 Reference<XDefaultNumberingProvider> xDefNum = DefaultNumberingProvider::create(m_xContext);
97 m_xNumTypeInfo.set(xDefNum, uno::UNO_QUERY);
98}
99
100const uno::Reference< text::XNumberingTypeInfo >&
102{
103 if (!m_pImpl->m_xNumTypeInfo.is())
104 {
105 m_pImpl->createNumTypeInfo();
106 }
107 return m_pImpl->m_xNumTypeInfo;
108}
109
110void SvXMLUnitConverter::SetCoreMeasureUnit(sal_Int16 const eCoreMeasureUnit/*css::util::MeasureUnit*/)
111{
112 m_pImpl->m_eCoreMeasureUnit = eCoreMeasureUnit;
113}
114
115void SvXMLUnitConverter::SetXMLMeasureUnit(sal_Int16 const eXMLMeasureUnit/*css::util::MeasureUnit*/)
116{
117 m_pImpl->m_eXMLMeasureUnit = eXMLMeasureUnit;
118}
119
121{
122 return m_pImpl->m_eXMLMeasureUnit;
123}
124
126{
127 return m_pImpl->m_eODFVersion;
128}
129
132{
133 m_pImpl->m_eODFVersion = nODFVersion;
134}
135
142 const uno::Reference<uno::XComponentContext>& xContext,
143 sal_Int16 const eCoreMeasureUnit,
144 sal_Int16 const eXMLMeasureUnit,
146: m_pImpl(new Impl(xContext, eCoreMeasureUnit, eXMLMeasureUnit, nODFVersion))
147{
148}
149
151{
152}
153
155{
156 sal_Int16 eUnit = util::MeasureUnit::INCH;
157 switch( nFieldUnit )
158 {
159 case FieldUnit::MM:
160 eUnit = util::MeasureUnit::MM;
161 break;
162 case FieldUnit::CM:
163 case FieldUnit::M:
164 case FieldUnit::KM:
165 eUnit = util::MeasureUnit::CM;
166 break;
167 case FieldUnit::TWIP:
168 eUnit = util::MeasureUnit::TWIP;
169 break;
170 case FieldUnit::POINT:
171 case FieldUnit::PICA:
172 eUnit = util::MeasureUnit::POINT;
173 break;
174 case FieldUnit::MM_100TH:
175 eUnit = util::MeasureUnit::MM_100TH;
176 break;
177 case FieldUnit::INCH:
178 eUnit = util::MeasureUnit::INCH;
179 break;
180 default:
181 assert(false);
182 break;
183 }
184 return eUnit;
185}
186
189 std::u16string_view rString,
190 sal_Int32 nMin, sal_Int32 nMax ) const
191{
192 return ::sax::Converter::convertMeasure( nValue, rString,
193 m_pImpl->m_eCoreMeasureUnit,
194 nMin, nMax );
195}
196
199 std::string_view rString,
200 sal_Int32 nMin, sal_Int32 nMax ) const
201{
202 return ::sax::Converter::convertMeasure( nValue, rString,
203 m_pImpl->m_eCoreMeasureUnit,
204 nMin, nMax );
205}
206
208void SvXMLUnitConverter::convertMeasureToXML( OUStringBuffer& rString,
209 sal_Int32 nMeasure ) const
210{
211 ::sax::Converter::convertMeasure( rString, nMeasure,
212 m_pImpl->m_eCoreMeasureUnit,
213 m_pImpl->m_eXMLMeasureUnit );
214}
215
217OUString SvXMLUnitConverter::convertMeasureToXML( sal_Int32 nMeasure ) const
218{
219 OUStringBuffer s;
221 m_pImpl->m_eCoreMeasureUnit,
222 m_pImpl->m_eXMLMeasureUnit );
223 return s.makeStringAndClear();
224}
225
230 std::u16string_view rValue,
232{
233 while( pMap->GetName() )
234 {
235 auto nameLength = pMap->GetNameLength();
236 if( static_cast<sal_Int32>(rValue.size()) == nameLength &&
237 rtl_ustr_asciil_reverseEquals_WithLength(
238 rValue.data(), pMap->GetName(), nameLength ) )
239 {
240 rEnum = pMap->GetValue();
241 return true;
242 }
243 ++pMap;
244 }
245
246 return false;
247}
248
252 sal_uInt16& rEnum,
253 std::u16string_view rValue,
255{
256 while( pMap->GetToken() != XML_TOKEN_INVALID )
257 {
258 if( IsXMLToken( rValue, pMap->GetToken() ) )
259 {
260 rEnum = pMap->GetValue();
261 return true;
262 }
263 ++pMap;
264 }
265 return false;
266}
267
271 sal_uInt16& rEnum,
272 std::string_view rValue,
274{
275 while( pMap->GetToken() != XML_TOKEN_INVALID )
276 {
277 if( IsXMLToken( rValue, pMap->GetToken() ) )
278 {
279 rEnum = pMap->GetValue();
280 return true;
281 }
282 ++pMap;
283 }
284 return false;
285}
286
292 OUStringBuffer& rBuffer,
293 sal_uInt16 nValue,
295 enum XMLTokenEnum eDefault)
296{
297 enum XMLTokenEnum eTok = eDefault;
298
299 while( pMap->GetToken() != XML_TOKEN_INVALID )
300 {
301 if( pMap->GetValue() == nValue )
302 {
303 eTok = pMap->GetToken();
304 break;
305 }
306 ++pMap;
307 }
308
309 // the map may have contained XML_TOKEN_INVALID
310 if( eTok == XML_TOKEN_INVALID )
311 eTok = eDefault;
312
313 if( eTok != XML_TOKEN_INVALID )
314 rBuffer.append( GetXMLToken(eTok) );
315
316 return (eTok != XML_TOKEN_INVALID);
317}
318
319static int lcl_gethex( int nChar )
320{
321 if( nChar >= '0' && nChar <= '9' )
322 return nChar - '0';
323 else if( nChar >= 'a' && nChar <= 'f' )
324 return nChar - 'a' + 10;
325 else if( nChar >= 'A' && nChar <= 'F' )
326 return nChar - 'A' + 10;
327 else
328 return 0;
329}
330
331const char aHexTab[] = "0123456789abcdef";
332
333
335void SvXMLUnitConverter::convertDouble(OUStringBuffer& rBuffer,
336 double fNumber) const
337{
338 ::sax::Converter::convertDouble(rBuffer, fNumber,
339 true/*bWriteUnits*/, m_pImpl->m_eCoreMeasureUnit, m_pImpl->m_eXMLMeasureUnit);
340}
341
344 std::u16string_view rString) const
345{
346 sal_Int16 const eSrcUnit = ::sax::Converter::GetUnitFromString(
347 rString, m_pImpl->m_eCoreMeasureUnit);
348
349 return ::sax::Converter::convertDouble(rValue, rString,
350 eSrcUnit, m_pImpl->m_eCoreMeasureUnit);
351}
352
355 std::string_view rString) const
356{
357 sal_Int16 const eSrcUnit = ::sax::Converter::GetUnitFromString(
358 rString, m_pImpl->m_eCoreMeasureUnit);
359
360 return ::sax::Converter::convertDouble(rValue, rString,
361 eSrcUnit, m_pImpl->m_eCoreMeasureUnit);
362}
363
365bool SvXMLUnitConverter::setNullDate(const css::uno::Reference <css::frame::XModel>& xModel)
366{
367 css::uno::Reference <css::util::XNumberFormatsSupplier> xNumberFormatsSupplier (xModel, css::uno::UNO_QUERY);
368 if (xNumberFormatsSupplier.is())
369 {
370 const css::uno::Reference <css::beans::XPropertySet> xPropertySet = xNumberFormatsSupplier->getNumberFormatSettings();
371 return xPropertySet.is() && (xPropertySet->getPropertyValue(XML_NULLDATE) >>= m_pImpl->m_aNullDate);
372 }
373 return false;
374}
375
377void SvXMLUnitConverter::convertDateTime(OUStringBuffer& rBuffer,
378 const double& fDateTime, bool const bAddTimeIf0AM)
379{
380 convertDateTime(rBuffer, fDateTime, m_pImpl->m_aNullDate, bAddTimeIf0AM);
381}
382
385 std::u16string_view rString) const
386{
387 return convertDateTime(fDateTime, rString, m_pImpl->m_aNullDate);
388}
389
392 std::string_view rString) const
393{
394 return convertDateTime(fDateTime, rString, m_pImpl->m_aNullDate);
395}
396
398void SvXMLUnitConverter::convertDateTime( OUStringBuffer& rBuffer,
399 const double& fDateTime,
400 const css::util::Date& aTempNullDate,
401 bool bAddTimeIf0AM )
402{
403 double fValue = fDateTime;
404 const sal_Int32 nDays = static_cast <sal_Int32> (::rtl::math::approxFloor (fValue));
405 Date aDate (aTempNullDate.Day, aTempNullDate.Month, aTempNullDate.Year);
406 aDate.AddDays( nDays);
407 fValue -= nDays;
408 const bool bHasTime = (fValue > 0.0);
409
410 sal_Int16 nTempYear = aDate.GetYear();
411 assert(nTempYear != 0);
412 if (nTempYear < 0)
413 {
414 rBuffer.append( '-');
415 nTempYear = -nTempYear;
416 }
417 if (nTempYear < 1000)
418 rBuffer.append( '0');
419 if (nTempYear < 100)
420 rBuffer.append( '0');
421 if (nTempYear < 10)
422 rBuffer.append( '0');
423 rBuffer.append( sal_Int32( nTempYear));
424 rBuffer.append( '-');
425 sal_uInt16 nTemp = aDate.GetMonth();
426 assert(1 <= nTemp && nTemp <= 12);
427 if (nTemp < 10)
428 rBuffer.append( '0');
429 rBuffer.append( sal_Int32( nTemp));
430 rBuffer.append( '-');
431 nTemp = aDate.GetDay();
432 assert(1 <= nTemp && nTemp <= 31);
433 if (nTemp < 10)
434 rBuffer.append( '0');
435 rBuffer.append( sal_Int32( nTemp));
436 if (!(bHasTime || bAddTimeIf0AM))
437 return;
438
439 double fCount;
440 if (nDays > 0)
441 fCount = ::rtl::math::approxFloor (log10(static_cast<double>(nDays))) + 1;
442 else if (nDays < 0)
443 fCount = ::rtl::math::approxFloor (log10(static_cast<double>(nDays * -1))) + 1;
444 else
445 fCount = 0.0;
446 const int nDigits = sal_Int16(fCount) + 4; // +4 for *86400 in seconds
447 const int nFractionDecimals = std::max( XML_MAXDIGITSCOUNT_TIME - nDigits, 0);
448
449 sal_uInt16 nHour, nMinute, nSecond;
450 double fFractionOfSecond;
451 // Pass the original date+time value for proper scaling and rounding.
452 tools::Time::GetClock( fDateTime, nHour, nMinute, nSecond, fFractionOfSecond, nFractionDecimals);
453
454 rBuffer.append( 'T');
455 if (nHour < 10)
456 rBuffer.append( '0');
457 rBuffer.append( sal_Int32( nHour));
458 rBuffer.append( ':');
459 if (nMinute < 10)
460 rBuffer.append( '0');
461 rBuffer.append( sal_Int32( nMinute));
462 rBuffer.append( ':');
463 if (nSecond < 10)
464 rBuffer.append( '0');
465 rBuffer.append( sal_Int32( nSecond));
466 if (!nFractionDecimals)
467 return;
468
469 // nFractionDecimals+1 to not round up what GetClock() carefully
470 // truncated.
471 OUString aFraction( ::rtl::math::doubleToUString( fFractionOfSecond,
472 rtl_math_StringFormat_F,
473 nFractionDecimals + 1, '.', true));
474 const sal_Int32 nLen = aFraction.getLength();
475 if ( nLen > 2 )
476 {
477 // Truncate nFractionDecimals+1 digit if it was not rounded to zero.
478 const sal_Int32 nCount = nLen - 2 - static_cast<int>(nLen > nFractionDecimals + 2);
479 rBuffer.append( '.');
480 rBuffer.append( aFraction.subView(2, nCount)); // strip 0.
481 }
482}
483
485template<typename V>
486static bool lcl_convertDateTime( double& fDateTime,
487 V rString, const css::util::Date& aTempNullDate)
488{
489 css::util::DateTime aDateTime;
490 bool bSuccess = ::sax::Converter::parseDateTime(aDateTime, rString);
491
492 if (bSuccess)
493 {
494 const Date aTmpNullDate(aTempNullDate.Day, aTempNullDate.Month, aTempNullDate.Year);
495 const Date aTempDate(aDateTime.Day, aDateTime.Month, aDateTime.Year);
496 const sal_Int32 nTage = aTempDate - aTmpNullDate;
497 double fTempDateTime = nTage;
498 double Hour = aDateTime.Hours;
499 double Min = aDateTime.Minutes;
500 double Sec = aDateTime.Seconds;
501 double NanoSec = aDateTime.NanoSeconds;
502 fTempDateTime += Hour / ::tools::Time::hourPerDay;
503 fTempDateTime += Min / ::tools::Time::minutePerDay;
504 fTempDateTime += Sec / ::tools::Time::secondPerDay;
505 fTempDateTime += NanoSec / ::tools::Time::nanoSecPerDay;
506 fDateTime = fTempDateTime;
507 }
508 return bSuccess;
509}
510
512 std::u16string_view rString, const css::util::Date& aTempNullDate)
513{
514 return lcl_convertDateTime(fDateTime, rString, aTempNullDate);
515}
518 std::string_view rString, const css::util::Date& aTempNullDate)
519{
520 return lcl_convertDateTime(fDateTime, rString, aTempNullDate);
521}
522
523
524SvXMLTokenEnumerator::SvXMLTokenEnumerator( std::u16string_view rString, sal_Unicode cSeparator /* = ' ' */ )
525: maTokenString( rString ), mnNextTokenPos(0), mcSeparator( cSeparator )
526{
527}
528
529bool SvXMLTokenEnumerator::getNextToken( std::u16string_view& rToken )
530{
531 if( std::u16string_view::npos == mnNextTokenPos )
532 return false;
533
534 size_t nTokenEndPos = maTokenString.find( mcSeparator, mnNextTokenPos );
535 if( nTokenEndPos != std::u16string_view::npos )
536 {
537 rToken = maTokenString.substr( mnNextTokenPos,
538 nTokenEndPos - mnNextTokenPos );
539 mnNextTokenPos = nTokenEndPos + 1;
540
541 // if the mnNextTokenPos is at the end of the string, we have
542 // to deliver an empty token
543 if( mnNextTokenPos > maTokenString.size() )
544 mnNextTokenPos = std::u16string_view::npos;
545 }
546 else
547 {
548 rToken = maTokenString.substr( mnNextTokenPos );
549 mnNextTokenPos = std::u16string_view::npos;
550 }
551
552 return true;
553}
554
555static bool lcl_getPositions(std::string_view _sValue, std::string_view& _rContentX, std::string_view& _rContentY, std::string_view& _rContentZ)
556{
557 if(_sValue.empty() || _sValue[0] != '(')
558 return false;
559
560 size_t nPos(1);
561 size_t nFound = _sValue.find(' ', nPos);
562
563 if(nFound == std::string_view::npos || nFound <= nPos)
564 return false;
565
566 _rContentX = _sValue.substr(nPos, nFound - nPos);
567
568 nPos = nFound + 1;
569 nFound = _sValue.find(' ', nPos);
570
571 if(nFound == std::string_view::npos || nFound <= nPos)
572 return false;
573
574 _rContentY = _sValue.substr(nPos, nFound - nPos);
575
576 nPos = nFound + 1;
577 nFound = _sValue.find(')', nPos);
578
579 if(nFound == std::string_view::npos || nFound <= nPos)
580 return false;
581
582 _rContentZ = _sValue.substr(nPos, nFound - nPos);
583 return true;
584
585}
586
588bool SvXMLUnitConverter::convertB3DVector( ::basegfx::B3DVector& rVector, std::string_view rValue )
589{
590 std::string_view aContentX,aContentY,aContentZ;
591 if ( !lcl_getPositions(rValue,aContentX,aContentY,aContentZ) )
592 return false;
593
594 rtl_math_ConversionStatus eStatus;
595
596 rVector.setX(::rtl::math::stringToDouble(aContentX, '.',
597 ',', &eStatus));
598
599 if( eStatus != rtl_math_ConversionStatus_Ok )
600 return false;
601
602 rVector.setY(::rtl::math::stringToDouble(aContentY, '.',
603 ',', &eStatus));
604
605 if( eStatus != rtl_math_ConversionStatus_Ok )
606 return false;
607
608 rVector.setZ(::rtl::math::stringToDouble(aContentZ, '.',
609 ',', &eStatus));
610
611
612 return ( eStatus == rtl_math_ConversionStatus_Ok );
613}
614
616void SvXMLUnitConverter::convertB3DVector( OUStringBuffer &rBuffer, const ::basegfx::B3DVector& rVector )
617{
618 rBuffer.append('(');
619 ::sax::Converter::convertDouble(rBuffer, rVector.getX());
620 rBuffer.append(' ');
621 ::sax::Converter::convertDouble(rBuffer, rVector.getY());
622 rBuffer.append(' ');
623 ::sax::Converter::convertDouble(rBuffer, rVector.getZ());
624 rBuffer.append(')');
625}
626
628bool SvXMLUnitConverter::convertPosition3D( drawing::Position3D& rPosition,
629 std::string_view rValue ) const
630{
631 std::string_view aContentX,aContentY,aContentZ;
632 if ( !lcl_getPositions(rValue,aContentX,aContentY,aContentZ) )
633 return false;
634
635 if ( !convertDouble( rPosition.PositionX, aContentX ) )
636 return false;
637 if ( !convertDouble( rPosition.PositionY, aContentY ) )
638 return false;
639 return convertDouble( rPosition.PositionZ, aContentZ );
640}
641
643void SvXMLUnitConverter::convertPosition3D( OUStringBuffer &rBuffer,
644 const drawing::Position3D& rPosition )
645{
646 rBuffer.append( '(' );
647 convertDouble( rBuffer, rPosition.PositionX );
648 rBuffer.append( ' ' );
649 convertDouble( rBuffer, rPosition.PositionY );
650 rBuffer.append( ' ' );
651 convertDouble( rBuffer, rPosition.PositionZ );
652 rBuffer.append( ')' );
653}
654
656 sal_Int16& rType,
657 const OUString& rNumFmt,
658 std::u16string_view rNumLetterSync,
659 bool bNumberNone ) const
660{
661 bool bRet = true;
662 bool bExt = false;
663
664 sal_Int32 nLen = rNumFmt.getLength();
665 if( 0 == nLen )
666 {
667 if( bNumberNone )
668 rType = NumberingType::NUMBER_NONE;
669 else
670 bRet = false;
671 }
672 else if( 1 == nLen )
673 {
674 switch( rNumFmt[0] )
675 {
676 case '1': rType = NumberingType::ARABIC; break;
677 case 'a': rType = NumberingType::CHARS_LOWER_LETTER; break;
678 case 'A': rType = NumberingType::CHARS_UPPER_LETTER; break;
679 case 'i': rType = NumberingType::ROMAN_LOWER; break;
680 case 'I': rType = NumberingType::ROMAN_UPPER; break;
681 default: bExt = true; break;
682 }
683 if( !bExt && IsXMLToken( rNumLetterSync, XML_TRUE ) )
684 {
685 switch( rType )
686 {
687 case NumberingType::CHARS_LOWER_LETTER:
688 rType = NumberingType::CHARS_LOWER_LETTER_N;
689 break;
690 case NumberingType::CHARS_UPPER_LETTER:
691 rType = NumberingType::CHARS_UPPER_LETTER_N;
692 break;
693 }
694 }
695 }
696 else
697 {
698 bExt = true;
699 }
700 if( bExt )
701 {
703 if( xInfo.is() && xInfo->hasNumberingType( rNumFmt ) )
704 {
705 rType = xInfo->getNumberingType( rNumFmt );
706 }
707 else
708 {
709 rType = NumberingType::ARABIC;
710 }
711 }
712
713 return bRet;
714}
715
716void SvXMLUnitConverter::convertNumFormat( OUStringBuffer& rBuffer,
717 sal_Int16 nType ) const
718{
719 enum XMLTokenEnum eFormat = XML_TOKEN_INVALID;
720 switch( nType )
721 {
722 case NumberingType::CHARS_UPPER_LETTER: eFormat = XML_A_UPCASE; break;
723 case NumberingType::CHARS_LOWER_LETTER: eFormat = XML_A; break;
724 case NumberingType::ROMAN_UPPER: eFormat = XML_I_UPCASE; break;
725 case NumberingType::ROMAN_LOWER: eFormat = XML_I; break;
726 case NumberingType::ARABIC: eFormat = XML_1; break;
727 case NumberingType::CHARS_UPPER_LETTER_N: eFormat = XML_A_UPCASE; break;
728 case NumberingType::CHARS_LOWER_LETTER_N: eFormat = XML_A; break;
729 case NumberingType::NUMBER_NONE: eFormat = XML__EMPTY; break;
730
731 case NumberingType::CHAR_SPECIAL:
732 case NumberingType::PAGE_DESCRIPTOR:
733 case NumberingType::BITMAP:
734 SAL_WARN_IF( eFormat == XML_TOKEN_INVALID, "xmloff", "invalid number format" );
735 break;
736 default:
737 break;
738 }
739
740 if( eFormat != XML_TOKEN_INVALID )
741 {
742 rBuffer.append( GetXMLToken(eFormat) );
743 }
744 else
745 {
747 if( xInfo.is() )
748 rBuffer.append( xInfo->getNumberingIdentifier( nType ) );
749 }
750}
751
752void SvXMLUnitConverter::convertNumLetterSync( OUStringBuffer& rBuffer,
753 sal_Int16 nType )
754{
755 enum XMLTokenEnum eSync = XML_TOKEN_INVALID;
756 switch( nType )
757 {
758 case NumberingType::CHARS_UPPER_LETTER:
759 case NumberingType::CHARS_LOWER_LETTER:
760 case NumberingType::ROMAN_UPPER:
761 case NumberingType::ROMAN_LOWER:
762 case NumberingType::ARABIC:
763 case NumberingType::NUMBER_NONE:
764 break;
765
766 case NumberingType::CHARS_UPPER_LETTER_N:
767 case NumberingType::CHARS_LOWER_LETTER_N:
768 eSync = XML_TRUE;
769 break;
770
771 case NumberingType::CHAR_SPECIAL:
772 case NumberingType::PAGE_DESCRIPTOR:
773 case NumberingType::BITMAP:
774 SAL_WARN_IF( eSync == XML_TOKEN_INVALID, "xmloff", "invalid number format" );
775 break;
776 }
777 if( eSync != XML_TOKEN_INVALID )
778 rBuffer.append( GetXMLToken(eSync) );
779}
780
781void SvXMLUnitConverter::convertPropertySet(uno::Sequence<beans::PropertyValue>& rProps,
782 const uno::Reference<beans::XPropertySet>& aProperties,
783 const std::initializer_list<std::u16string_view>* pOmitFalseValues)
784{
785 uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = aProperties->getPropertySetInfo();
786 if (!xPropertySetInfo.is())
787 return;
788
789 const uno::Sequence< beans::Property > aProps = xPropertySetInfo->getProperties();
790 if (aProps.hasElements())
791 {
792 std::vector<beans::PropertyValue> aPropsVec;
793 for (const auto& rProp : aProps)
794 {
795 uno::Any aPropertyValue = aProperties->getPropertyValue(rProp.Name);
796 if (pOmitFalseValues && aPropertyValue.has<bool>() && !aPropertyValue.get<bool>())
797 {
798 const std::initializer_list<std::u16string_view>& rOmitFalseValues = *pOmitFalseValues;
799 if (std::find(rOmitFalseValues.begin(), rOmitFalseValues.end(), rProp.Name) != rOmitFalseValues.end())
800 {
801 continue;
802 }
803 }
804
805 beans::PropertyValue aValue;
806 aValue.Name = rProp.Name;
807 aValue.Value = aPropertyValue;
808 aPropsVec.push_back(aValue);
809 }
810 rProps = comphelper::containerToSequence(aPropsVec);
811 }
812}
813
814void SvXMLUnitConverter::convertPropertySet(uno::Reference<beans::XPropertySet> const & rProperties,
815 const uno::Sequence<beans::PropertyValue>& aProps)
816{
817 if (aProps.hasElements())
818 {
819 uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = rProperties->getPropertySetInfo();
820 if (xPropertySetInfo.is())
821 {
822 for (const auto& rProp : aProps)
823 {
824 if (xPropertySetInfo->hasPropertyByName(rProp.Name))
825 rProperties->setPropertyValue(rProp.Name, rProp.Value);
826 }
827 }
828 }
829}
830
831
833 const OUString& rName,
834 bool *pEncoded ) const
835{
836 if( pEncoded )
837 *pEncoded = false;
838
839 sal_Int32 nLen = rName.getLength();
840 OUStringBuffer aBuffer( nLen*2 );
841
842 for( sal_Int32 i = 0; i < nLen; i++ )
843 {
844 sal_Unicode c = rName[i];
845 bool bValidChar = false;
846 if( c < 0x00ffU )
847 {
848 bValidChar =
849 (c >= 0x0041 && c <= 0x005a) ||
850 (c >= 0x0061 && c <= 0x007a) ||
851 (c >= 0x00c0 && c <= 0x00d6) ||
852 (c >= 0x00d8 && c <= 0x00f6) ||
853 (c >= 0x00f8 && c <= 0x00ff) ||
854 ( i > 0 && ( (c >= 0x0030 && c <= 0x0039) ||
855 c == 0x00b7 || c == '-' || c == '.') );
856 }
857 else
858 {
859 if( (c >= 0xf900U && c <= 0xfffeU) ||
860 (c >= 0x20ddU && c <= 0x20e0U))
861 {
862 bValidChar = false;
863 }
864 else if( (c >= 0x02bbU && c <= 0x02c1U) || c == 0x0559 ||
865 c == 0x06e5 || c == 0x06e6 )
866 {
867 bValidChar = true;
868 }
869 else if( c == 0x0387 )
870 {
871 bValidChar = i > 0;
872 }
873 else
874 {
875 if (!m_pImpl->m_xCharClass.is())
876 {
877 m_pImpl->m_xCharClass = CharacterClassification::create( m_pImpl->m_xContext );
878 }
879 sal_Int16 nType = m_pImpl->m_xCharClass->getType(rName, i);
880
881 switch( nType )
882 {
883 case UnicodeType::UPPERCASE_LETTER: // Lu
884 case UnicodeType::LOWERCASE_LETTER: // Ll
885 case UnicodeType::TITLECASE_LETTER: // Lt
886 case UnicodeType::OTHER_LETTER: // Lo
887 case UnicodeType::LETTER_NUMBER: // Nl
888 bValidChar = true;
889 break;
890 case UnicodeType::NON_SPACING_MARK: // Ms
891 case UnicodeType::ENCLOSING_MARK: // Me
892 case UnicodeType::COMBINING_SPACING_MARK: //Mc
893 case UnicodeType::MODIFIER_LETTER: // Lm
894 case UnicodeType::DECIMAL_DIGIT_NUMBER: // Nd
895 bValidChar = i > 0;
896 break;
897 }
898 }
899 }
900 if( bValidChar )
901 {
902 aBuffer.append( c );
903 }
904 else
905 {
906 aBuffer.append( '_' );
907 if( c > 0x0fff )
908 aBuffer.append( static_cast< sal_Unicode >(
909 aHexTab[ (c >> 12) & 0x0f ] ) );
910 if( c > 0x00ff )
911 aBuffer.append( static_cast< sal_Unicode >(
912 aHexTab[ (c >> 8) & 0x0f ] ) );
913 if( c > 0x000f )
914 aBuffer.append( static_cast< sal_Unicode >(
915 aHexTab[ (c >> 4) & 0x0f ] ) );
916 aBuffer.append(
917 OUStringChar(static_cast< sal_Unicode >( aHexTab[ c & 0x0f ] ) )
918 + "_" );
919 if( pEncoded )
920 *pEncoded = true;
921 }
922 }
923
924 // check for length
925 if( aBuffer.getLength() > ((1<<15)-1) )
926 {
927 aBuffer = rName;
928 if( pEncoded )
929 *pEncoded = false;
930 }
931
932
933 return aBuffer.makeStringAndClear();
934}
935
937bool SvXMLUnitConverter::convertHex( sal_uInt32& nVal, std::u16string_view rValue )
938{
939 if( rValue.size() != 8 )
940 return false;
941
942 nVal = 0;
943 for ( int i = 0; i < 8; i++ )
944 {
945 nVal = ( nVal << 4 )
946 | sal::static_int_cast< sal_uInt32 >( lcl_gethex( rValue[i] ) );
947 }
948
949 return true;
950}
951
953void SvXMLUnitConverter::convertHex( OUStringBuffer& rBuffer,
954 sal_uInt32 nVal )
955{
956 for ( int i = 0; i < 8; i++ )
957 {
958 rBuffer.append( sal_Unicode( aHexTab[ nVal >> 28 ] ) );
959 nVal <<= 4;
960 }
961}
962
963/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
PropertiesInfo aProperties
void AddDays(sal_Int32 nAddDays)
sal_Int16 GetYear() const
sal_uInt16 GetDay() const
sal_uInt16 GetMonth() const
std::u16string_view maTokenString
Definition: xmluconv.hxx:59
bool getNextToken(std::u16string_view &rToken)
Definition: xmluconv.cxx:529
sal_Unicode mcSeparator
Definition: xmluconv.hxx:61
SvXMLTokenEnumerator(std::u16string_view rString, sal_Unicode cSeparator=u' ')
Definition: xmluconv.cxx:524
bool convertPosition3D(css::drawing::Position3D &rPosition, std::string_view rValue) const
convert string to Position3D
SvtSaveOptions::ODFSaneDefaultVersion getSaneDefaultVersion() const
ODF version, only when exporting.
Definition: xmluconv.cxx:125
bool convertNumFormat(sal_Int16 &rType, const OUString &rNumFormat, std::u16string_view rNumLetterSync, bool bNumberNone=false) const
convert num-format and num-letter-sync values to NumberingType
Definition: xmluconv.cxx:655
struct SAL_DLLPRIVATE Impl
Definition: xmluconv.hxx:88
bool convertMeasureToCore(sal_Int32 &rValue, std::u16string_view rString, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32) const
convert string to measure with meCoreMeasureUnit, using optional min and max values
Definition: xmluconv.cxx:188
SvXMLUnitConverter(const SvXMLUnitConverter &)=delete
void convertDateTime(OUStringBuffer &rBuffer, const double &fDateTime, bool const bAddTimeIf0AM=false)
convert double to ISO Date Time String
Definition: xmluconv.cxx:377
OUString encodeStyleName(const OUString &rName, bool *pEncoded=nullptr) const
Definition: xmluconv.cxx:832
void SetCoreMeasureUnit(sal_Int16 const eCoreMeasureUnit)
sets the default unit for numerical measures
Definition: xmluconv.cxx:110
static void convertPropertySet(css::uno::Sequence< css::beans::PropertyValue > &rProps, const css::uno::Reference< css::beans::XPropertySet > &aProperties, const std::initializer_list< std::u16string_view > *pOmitFalseValues=nullptr)
void SetXMLMeasureUnit(sal_Int16 const eXMLMeasureUnit)
sets the default unit for textual measures
Definition: xmluconv.cxx:115
static bool convertHex(sal_uInt32 &nVal, std::u16string_view rValue)
convert string (hex) to number (sal_uInt32)
Definition: xmluconv.cxx:937
::std::unique_ptr< Impl > m_pImpl
Definition: xmluconv.hxx:89
static sal_Int16 GetMeasureUnit(FieldUnit const nFieldUnit)
Definition: xmluconv.cxx:154
sal_Int16 GetXMLMeasureUnit() const
gets the default unit for textual measures
Definition: xmluconv.cxx:120
void convertDouble(OUStringBuffer &rBuffer, double fNumber) const
convert double number to string (using ::rtl::math) and DO convert to export MapUnit using meCoreMeas...
Definition: xmluconv.cxx:335
bool setNullDate(const css::uno::Reference< css::frame::XModel > &xModel)
get the Null Date of the XModel and set it to the UnitConverter
Definition: xmluconv.cxx:365
static bool convertB3DVector(::basegfx::B3DVector &rVector, std::string_view rValue)
convert string to basegfx::B3DVector
Definition: xmluconv.cxx:588
void convertMeasureToXML(OUStringBuffer &rBuffer, sal_Int32 nMeasure) const
convert measure to string: from meCoreMeasureUnit to meXMLMeasureUnit
Definition: xmluconv.cxx:208
void overrideSaneDefaultVersion(SvtSaveOptions::ODFSaneDefaultVersion const)
Definition: xmluconv.cxx:130
static void convertNumLetterSync(OUStringBuffer &rBuffer, sal_Int16 nType)
Definition: xmluconv.cxx:752
static bool convertEnumImpl(sal_uInt16 &rEnum, std::u16string_view rValue, const SvXMLEnumMapEntry< sal_uInt16 > *pMap)
convert string to enum using given token map, if the enum is not found in the map,...
Definition: xmluconv.cxx:251
const css::uno::Reference< css::text::XNumberingTypeInfo > & getNumTypeInfo() const
gets XNumberingTypeInfo
Definition: xmluconv.cxx:101
void setX(TYPE fX)
void setY(TYPE fY)
void setZ(TYPE fZ)
static void convertDouble(OUStringBuffer &rBuffer, double fNumber, bool bWriteUnits, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
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)
static bool parseDateTime(css::util::DateTime &rDateTime, std::u16string_view rString)
static sal_Int16 GetUnitFromString(std::u16string_view rString, sal_Int16 nDefaultUnit)
static const sal_Int64 nanoSecPerDay
static void GetClock(double fTimeInDays, sal_uInt16 &nHour, sal_uInt16 &nMinute, sal_uInt16 &nSecond, double &fFractionOfSecond, int nFractionDecimals)
static const sal_Int64 minutePerDay
static const sal_Int64 hourPerDay
static const sal_Int64 secondPerDay
int nCount
float u
FieldUnit
sal_Int16 nValue
sal_uInt16 nPos
#define SAL_WARN_IF(condition, area, stream)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
int i
Handling of tokens in XML:
XMLTokenEnum
The enumeration of all XML tokens.
Definition: xmltoken.hxx:50
bool IsXMLToken(std::u16string_view rString, enum XMLTokenEnum eToken)
compare eToken to the string
Definition: xmltoken.cxx:3597
const OUString & GetXMLToken(enum XMLTokenEnum eToken)
return the OUString representation for eToken
Definition: xmltoken.cxx:3541
QPRO_FUNC_TYPE nType
Map a const char* (with length) to a sal_uInt16 value.
Definition: xmlement.hxx:71
EnumT GetValue() const
Definition: xmlement.hxx:81
const char * GetName() const
Definition: xmlement.hxx:79
sal_Int32 GetNameLength() const
Definition: xmlement.hxx:80
Impl(uno::Reference< uno::XComponentContext > xContext, sal_Int16 const eCoreMeasureUnit, sal_Int16 const eXMLMeasureUnit, SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)
Definition: xmluconv.cxx:77
sal_Int16 m_eCoreMeasureUnit
Definition: xmluconv.cxx:69
uno::Reference< uno::XComponentContext > m_xContext
Definition: xmluconv.cxx:75
uno::Reference< text::XNumberingTypeInfo > m_xNumTypeInfo
Definition: xmluconv.cxx:73
uno::Reference< i18n::XCharacterClassification > m_xCharClass
Definition: xmluconv.cxx:74
void createNumTypeInfo() const
Definition: xmluconv.cxx:94
sal_Int16 m_eXMLMeasureUnit
Definition: xmluconv.cxx:70
SvtSaveOptions::ODFSaneDefaultVersion m_eODFVersion
Definition: xmluconv.cxx:71
Reference< XModel > xModel
sal_uInt16 sal_Unicode
signed char sal_Int8
std::unique_ptr< char[]> aBuffer
const char aHexTab[]
Definition: xmluconv.cxx:331
constexpr OUStringLiteral XML_NULLDATE
Definition: xmluconv.cxx:65
static bool lcl_convertDateTime(double &fDateTime, V rString, const css::util::Date &aTempNullDate)
convert ISO Date Time String to double
Definition: xmluconv.cxx:486
const sal_Int8 XML_MAXDIGITSCOUNT_TIME
Definition: xmluconv.cxx:64
static int lcl_gethex(int nChar)
Definition: xmluconv.cxx:319
static bool lcl_getPositions(std::string_view _sValue, std::string_view &_rContentX, std::string_view &_rContentY, std::string_view &_rContentZ)
Definition: xmluconv.cxx:555