Avoid potential negative array index access to cached text.
[LibreOffice.git] / xmloff / source / xforms / SchemaRestrictionContext.cxx
blob0a1114f7d40c75ae2e0ed23adb0dacecaa96f7ed
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include "SchemaRestrictionContext.hxx"
22 #include "xformsapi.hxx"
24 #include <utility>
25 #include <xmloff/xmltoken.hxx>
26 #include <xmloff/namespacemap.hxx>
27 #include <xmloff/xmlnamespace.hxx>
28 #include <xmloff/xmltkmap.hxx>
29 #include <xmloff/xmlimp.hxx>
31 #include <sax/tools/converter.hxx>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/util/Date.hpp>
35 #include <com/sun/star/util/Time.hpp>
36 #include <com/sun/star/util/DateTime.hpp>
37 #include <com/sun/star/util/Duration.hpp>
38 #include <com/sun/star/xforms/XDataTypeRepository.hpp>
39 #include <com/sun/star/xsd/DataTypeClass.hpp>
40 #include <com/sun/star/xsd/WhiteSpaceTreatment.hpp>
42 #include <o3tl/string_view.hxx>
43 #include <sal/log.hxx>
44 #include <comphelper/diagnose_ex.hxx>
47 using com::sun::star::uno::Reference;
48 using com::sun::star::uno::Exception;
49 using com::sun::star::uno::Any;
50 using namespace com::sun::star;
51 using com::sun::star::util::Duration;
52 using com::sun::star::xml::sax::XFastAttributeList;
53 using com::sun::star::xforms::XDataTypeRepository;
54 using namespace xmloff::token;
57 SchemaRestrictionContext::SchemaRestrictionContext(
58 SvXMLImport& rImport,
59 Reference<css::xforms::XDataTypeRepository> const & rRepository,
60 OUString sTypeName ) :
61 TokenContext( rImport ),
62 mxRepository( rRepository ),
63 msTypeName(std::move( sTypeName ))
65 SAL_WARN_IF( !mxRepository.is(), "xmloff", "need repository" );
68 void SchemaRestrictionContext::CreateDataType()
70 // only do something if we don't have a data type already
71 if( mxDataType.is() )
72 return;
74 SAL_WARN_IF( msBaseName.isEmpty(), "xmloff", "no base name?" );
75 SAL_WARN_IF( !mxRepository.is(), "xmloff", "no repository?" );
77 try
79 mxDataType =
80 mxRepository->cloneDataType(
81 xforms_getBasicTypeName( mxRepository,
82 GetImport().GetNamespaceMap(),
83 msBaseName ),
84 msTypeName );
86 catch( const Exception& )
88 TOOLS_WARN_EXCEPTION("xmloff", "exception during type creation");
90 SAL_WARN_IF( !mxDataType.is(), "xmloff", "can't create type" );
93 void SchemaRestrictionContext::HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter )
95 switch (aIter.getToken() & TOKEN_MASK)
97 case XML_BASE:
98 msBaseName = aIter.toString();
99 break;
103 typedef Any (*convert_t)( const OUString& );
105 static Any xforms_string( const OUString& rValue )
107 return Any( rValue );
110 static Any xforms_int32( const OUString& rValue )
112 sal_Int32 nValue;
113 bool bSuccess = ::sax::Converter::convertNumber( nValue, rValue );
114 return bSuccess ? Any( nValue ) : Any();
117 static Any xforms_int16( const OUString& rValue )
119 sal_Int32 nValue;
120 bool bSuccess = ::sax::Converter::convertNumber( nValue, rValue );
121 return bSuccess ? Any( static_cast<sal_Int16>( nValue ) ) : Any();
124 static Any xforms_whitespace( const OUString& rValue )
126 Any aValue;
127 if( IsXMLToken( rValue, XML_PRESERVE ) )
128 aValue <<= css::xsd::WhiteSpaceTreatment::Preserve;
129 else if( IsXMLToken( rValue, XML_REPLACE ) )
130 aValue <<= css::xsd::WhiteSpaceTreatment::Replace;
131 else if( IsXMLToken( rValue, XML_COLLAPSE ) )
132 aValue <<= css::xsd::WhiteSpaceTreatment::Collapse;
133 return aValue;
136 static Any xforms_double( const OUString& rValue )
138 double fValue;
139 bool bSuccess = ::sax::Converter::convertDouble( fValue, rValue );
140 return bSuccess ? Any( fValue ) : Any();
143 static Any xforms_date( const OUString& rValue )
145 Any aAny;
147 // parse ISO date
148 sal_Int32 nPos1 = rValue.indexOf( '-' );
149 sal_Int32 nPos2 = rValue.indexOf( '-', nPos1 + 1 );
150 if( nPos1 > 0 && nPos2 > 0 )
152 util::Date aDate;
153 aDate.Year = static_cast<sal_uInt16>(
154 o3tl::toInt32(rValue.subView( 0, nPos1 )) );
155 aDate.Month = static_cast<sal_uInt16>(
156 o3tl::toInt32(rValue.subView( nPos1 + 1, nPos2 - nPos1 - 1 )) );
157 aDate.Day = static_cast<sal_uInt16>(
158 o3tl::toInt32(rValue.subView( nPos2 + 1 )) );
159 aAny <<= aDate;
161 return aAny;
164 static Any xforms_dateTime( const OUString& rValue )
166 util::DateTime aDateTime;
167 bool const bSuccess = ::sax::Converter::parseDateTime(aDateTime, rValue);
168 return bSuccess ? Any( aDateTime ) : Any();
171 static Any xforms_time( const OUString& rValue )
173 Any aAny;
174 Duration aDuration;
175 if (::sax::Converter::convertDuration( aDuration, rValue ))
177 css::util::Time aTime;
178 aTime.Hours = aDuration.Hours;
179 aTime.Minutes = aDuration.Minutes;
180 aTime.Seconds = aDuration.Seconds;
181 aTime.NanoSeconds = aDuration.NanoSeconds;
182 aAny <<= aTime;
184 return aAny;
188 SvXMLImportContext* SchemaRestrictionContext::HandleChild(
189 sal_Int32 nElementToken,
190 const Reference<XFastAttributeList>& xAttrList )
192 // find value
193 OUString sValue;
194 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
196 if( ( aIter.getToken() & TOKEN_MASK) == XML_VALUE )
198 sValue = aIter.toString();
199 break;
203 // determine property name + suitable converter
204 OUString sPropertyName;
205 convert_t pConvert = nullptr;
206 switch( nElementToken & TOKEN_MASK )
208 case XML_LENGTH:
209 sPropertyName = "Length";
210 pConvert = &xforms_int32;
211 break;
212 case XML_MINLENGTH:
213 sPropertyName = "MinLength";
214 pConvert = &xforms_int32;
215 break;
216 case XML_MAXLENGTH:
217 sPropertyName = "MaxLength";
218 pConvert = &xforms_int32;
219 break;
220 case XML_TOTALDIGITS:
221 sPropertyName = "TotalDigits";
222 pConvert = &xforms_int32;
223 break;
224 case XML_FRACTIONDIGITS:
225 sPropertyName = "FractionDigits";
226 pConvert = &xforms_int32;
227 break;
228 case XML_PATTERN:
229 sPropertyName = "Pattern";
230 pConvert = &xforms_string;
231 break;
232 case XML_WHITESPACE:
233 sPropertyName = "WhiteSpace";
234 pConvert = &xforms_whitespace;
235 break;
236 case XML_MININCLUSIVE:
237 case XML_MINEXCLUSIVE:
238 case XML_MAXINCLUSIVE:
239 case XML_MAXEXCLUSIVE:
241 // these attributes are mapped to different properties.
242 // To determine the property name, we use an attribute
243 // dependent prefix and a type dependent suffix. The
244 // converter is only type dependent.
246 // first, attribute-dependent prefix
247 switch( nElementToken & TOKEN_MASK )
249 case XML_MININCLUSIVE:
250 sPropertyName = "MinInclusive";
251 break;
252 case XML_MINEXCLUSIVE:
253 sPropertyName = "MinExclusive";
254 break;
255 case XML_MAXINCLUSIVE:
256 sPropertyName = "MaxInclusive";
257 break;
258 case XML_MAXEXCLUSIVE:
259 sPropertyName = "MaxExclusive";
260 break;
263 // second, type-dependent suffix + converter
264 switch( xforms_getTypeClass( mxRepository,
265 GetImport().GetNamespaceMap(),
266 msBaseName ) )
268 case css::xsd::DataTypeClass::DECIMAL:
269 case css::xsd::DataTypeClass::DOUBLE:
270 case css::xsd::DataTypeClass::FLOAT:
271 sPropertyName += "Double";
272 pConvert = &xforms_double;
273 break;
274 case css::xsd::DataTypeClass::DATETIME:
275 sPropertyName += "DateTime";
276 pConvert = &xforms_dateTime;
277 break;
278 case css::xsd::DataTypeClass::DATE:
279 sPropertyName += "Date";
280 pConvert = &xforms_date;
281 break;
282 case css::xsd::DataTypeClass::TIME:
283 sPropertyName += "Time";
284 pConvert = &xforms_time;
285 break;
286 case css::xsd::DataTypeClass::gYear:
287 case css::xsd::DataTypeClass::gDay:
288 case css::xsd::DataTypeClass::gMonth:
289 sPropertyName += "Int";
290 pConvert = &xforms_int16;
291 break;
293 case css::xsd::DataTypeClass::STRING:
294 case css::xsd::DataTypeClass::anyURI:
295 case css::xsd::DataTypeClass::BOOLEAN:
296 // invalid: These shouldn't have min/max-inclusive
297 break;
299 /* data types not yet supported:
300 case css::xsd::DataTypeClass::DURATION:
301 case css::xsd::DataTypeClass::gYearMonth:
302 case css::xsd::DataTypeClass::gMonthDay:
303 case css::xsd::DataTypeClass::hexBinary:
304 case css::xsd::DataTypeClass::base64Binary:
305 case css::xsd::DataTypeClass::QName:
306 case css::xsd::DataTypeClass::NOTATION:
310 break;
312 default:
313 OSL_FAIL( "unknown facet" );
316 // finally, set the property
317 CreateDataType();
318 if( mxDataType.is()
319 && !sPropertyName.isEmpty()
320 && pConvert != nullptr
321 && mxDataType->getPropertySetInfo()->hasPropertyByName(sPropertyName) )
325 mxDataType->setPropertyValue( sPropertyName, pConvert( sValue ) );
327 catch( const Exception& )
329 ; // can't set property? Then ignore.
333 return new SvXMLImportContext( GetImport() );
336 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */