1 /*
2 * Copyright (c) 2011-2015, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include "IntegerParameterType.h"
31 #include <stdlib.h>
32 #include <sstream>
33 #include <iomanip>
34 #include "ParameterAccessContext.h"
35 #include <assert.h>
36 #include "ParameterAdaptation.h"
37 #include "Utility.h"
38 #include <errno.h>
39
40 #define base CParameterType
41
42 using std::string;
43 using std::ostringstream;
44
CIntegerParameterType(const string & strName)45 CIntegerParameterType::CIntegerParameterType(const string& strName) : base(strName), _uiMin(0), _uiMax(uint32_t(-1))
46 {
47 }
48
49 // Kind
getKind() const50 string CIntegerParameterType::getKind() const
51 {
52 return "IntegerParameter";
53 }
54
55 // Deal with adaption node
childrenAreDynamic() const56 bool CIntegerParameterType::childrenAreDynamic() const
57 {
58 return true;
59 }
60
61 // Element properties
showProperties(string & strResult) const62 void CIntegerParameterType::showProperties(string& strResult) const
63 {
64 base::showProperties(strResult);
65
66 // Sign
67 strResult += "Signed: ";
68 strResult += _bSigned ? "yes" : "no";
69 strResult += "\n";
70
71 // Min
72 strResult += "Min: ";
73 strResult += _bSigned ? CUtility::toString((int32_t)_uiMin) : CUtility::toString(_uiMin);
74 strResult += "\n";
75
76 // Max
77 strResult += "Max: ";
78 strResult += _bSigned ? CUtility::toString((int32_t)_uiMax) : CUtility::toString(_uiMax);
79 strResult += "\n";
80
81 // Check if there's an adaptation object available
82 const CParameterAdaptation* pParameterAdaption = getParameterAdaptation();
83
84 if (pParameterAdaption) {
85
86 // Display adaptation properties
87 strResult += "Adaptation:\n";
88
89 pParameterAdaption->showProperties(strResult);
90 }
91 }
92
fromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)93 bool CIntegerParameterType::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
94 {
95 // Sign
96 _bSigned = xmlElement.getAttributeBoolean("Signed");
97
98 // Size in bits
99 uint32_t uiSizeInBits = xmlElement.getAttributeInteger("Size");
100
101 // Size
102 setSize(uiSizeInBits / 8);
103
104 // Min / Max
105 if (_bSigned) {
106
107 // Signed means we have one less util bit
108 uiSizeInBits--;
109
110 if (xmlElement.hasAttribute("Min")) {
111
112 _uiMin = (uint32_t)xmlElement.getAttributeSignedInteger("Min");
113 } else {
114
115 _uiMin = 1UL << uiSizeInBits;
116
117 }
118 signExtend((int32_t&)_uiMin);
119
120 if (xmlElement.hasAttribute("Max")) {
121
122 _uiMax = (uint32_t)xmlElement.getAttributeSignedInteger("Max");
123
124 signExtend((int32_t&)_uiMax);
125 } else {
126
127 _uiMax = (1UL << uiSizeInBits) - 1;
128 }
129 } else {
130 if (xmlElement.hasAttribute("Min")) {
131
132 _uiMin = xmlElement.getAttributeInteger("Min");
133 } else {
134
135 _uiMin = 0;
136 }
137 if (xmlElement.hasAttribute("Max")) {
138
139 _uiMax = xmlElement.getAttributeInteger("Max");
140 } else {
141
142 _uiMax = (uint32_t)-1L >> (8 * sizeof(uint32_t) - uiSizeInBits);
143 }
144 }
145
146 // Base
147 return base::fromXml(xmlElement, serializingContext);
148 }
149
150 // Conversion (tuning)
toBlackboard(const string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const151 bool CIntegerParameterType::toBlackboard(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
152 {
153 // Hexa
154 bool bValueProvidedAsHexa = !strValue.compare(0, 2, "0x");
155
156 // Get integer value from the string provided
157 int64_t iData;
158
159 if (!convertValueFromString(strValue, iData, parameterAccessContext)) {
160
161 return false;
162 }
163
164 // Check against Min / Max
165 if (_bSigned) {
166
167 if (bValueProvidedAsHexa && isEncodable((uint64_t)iData, !bValueProvidedAsHexa)) {
168
169 // Sign extend
170 signExtend(iData);
171 }
172
173 if (!checkValueAgainstRange<int64_t>(strValue, iData, (int32_t)_uiMin, (int32_t)_uiMax, parameterAccessContext, bValueProvidedAsHexa)) {
174
175 return false;
176 }
177 } else {
178
179 if (!checkValueAgainstRange<uint64_t>(strValue, iData, _uiMin, _uiMax, parameterAccessContext, bValueProvidedAsHexa)) {
180
181 return false;
182 }
183 }
184
185 uiValue = (uint32_t)iData;
186
187 return true;
188 }
189
fromBlackboard(string & strValue,const uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const190 bool CIntegerParameterType::fromBlackboard(string& strValue, const uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
191 {
192 // Check unsigned value is encodable
193 assert(isEncodable(uiValue, false));
194
195 // Format
196 ostringstream strStream;
197
198 // Take care of format
199 if (parameterAccessContext.valueSpaceIsRaw() && parameterAccessContext.outputRawFormatIsHex()) {
200
201 // Hexa display with unecessary bits cleared out
202 strStream << "0x" << std::hex << std::uppercase << std::setw(getSize()*2) << std::setfill('0') << uiValue;
203 } else {
204
205 if (_bSigned) {
206
207 int32_t iValue = uiValue;
208
209 // Sign extend
210 signExtend(iValue);
211
212 strStream << iValue;
213 } else {
214
215 strStream << uiValue;
216 }
217 }
218
219 strValue = strStream.str();
220
221 return true;
222 }
223
224 // Value access
225 // Integer
toBlackboard(uint32_t uiUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const226 bool CIntegerParameterType::toBlackboard(uint32_t uiUserValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
227 {
228 if (uiUserValue < _uiMin || uiUserValue > _uiMax) {
229
230 parameterAccessContext.setError("Value out of range");
231
232 return false;
233 }
234 // Do assign
235 uiValue = uiUserValue;
236
237 return true;
238 }
239
fromBlackboard(uint32_t & uiUserValue,uint32_t uiValue,CParameterAccessContext & parameterAccessContext) const240 bool CIntegerParameterType::fromBlackboard(uint32_t& uiUserValue, uint32_t uiValue, CParameterAccessContext& parameterAccessContext) const
241 {
242 (void)parameterAccessContext;
243
244 // Do assign
245 uiUserValue = uiValue;
246
247 return true;
248 }
249
250 // Signed Integer
toBlackboard(int32_t iUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const251 bool CIntegerParameterType::toBlackboard(int32_t iUserValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
252 {
253 if (iUserValue < (int32_t)_uiMin || iUserValue > (int32_t)_uiMax) {
254
255 parameterAccessContext.setError("Value out of range");
256
257 return false;
258 }
259 // Do assign
260 uiValue = iUserValue;
261
262 return true;
263 }
264
fromBlackboard(int32_t & iUserValue,uint32_t uiValue,CParameterAccessContext & parameterAccessContext) const265 bool CIntegerParameterType::fromBlackboard(int32_t& iUserValue, uint32_t uiValue, CParameterAccessContext& parameterAccessContext) const
266 {
267 (void)parameterAccessContext;
268
269 int32_t iValue = uiValue;
270
271 // Sign extend
272 signExtend(iValue);
273
274 // Do assign
275 iUserValue = iValue;
276
277 return true;
278 }
279
280 // Double
toBlackboard(double dUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const281 bool CIntegerParameterType::toBlackboard(double dUserValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
282 {
283 // Check if there's an adaptation object available
284 const CParameterAdaptation* pParameterAdaption = getParameterAdaptation();
285
286 if (!pParameterAdaption) {
287
288 // Reject request and let upper class handle the error
289 return base::toBlackboard(dUserValue, uiValue, parameterAccessContext);
290 }
291
292 // Do the conversion
293 int64_t iConvertedValue = pParameterAdaption->fromUserValue(dUserValue);
294
295 // Check against range
296 if (_bSigned) {
297
298 if (iConvertedValue < (int32_t)_uiMin || iConvertedValue > (int32_t)_uiMax) {
299
300 parameterAccessContext.setError("Value out of range");
301
302 return false;
303 }
304 } else {
305
306 if (iConvertedValue < _uiMin || iConvertedValue > _uiMax) {
307
308 parameterAccessContext.setError("Value out of range");
309
310 return false;
311 }
312 }
313
314 // Do assign
315 uiValue = (uint32_t)iConvertedValue;
316
317 return true;
318 }
319
fromBlackboard(double & dUserValue,uint32_t uiValue,CParameterAccessContext & parameterAccessContext) const320 bool CIntegerParameterType::fromBlackboard(double& dUserValue, uint32_t uiValue, CParameterAccessContext& parameterAccessContext) const
321 {
322 // Check if there's an adaptation object available
323 const CParameterAdaptation* pParameterAdaption = getParameterAdaptation();
324
325 if (!pParameterAdaption) {
326
327 // Reject request and let upper class handle the error
328 return base::fromBlackboard(dUserValue, uiValue, parameterAccessContext);
329 }
330
331 int64_t iValueToConvert;
332
333 // Deal with signed data
334 if (_bSigned) {
335
336 int32_t iValue = uiValue;
337
338 signExtend(iValue);
339
340 iValueToConvert = iValue;
341 } else {
342
343 iValueToConvert = uiValue;
344 }
345
346 // Do the conversion
347 dUserValue = pParameterAdaption->toUserValue(iValueToConvert);
348
349 return true;
350 }
351
352 // Default value handling (simulation only)
getDefaultValue() const353 uint32_t CIntegerParameterType::getDefaultValue() const
354 {
355 return _uiMin;
356 }
357
toPlainInteger(int iSizeOptimizedData) const358 int CIntegerParameterType::toPlainInteger(int iSizeOptimizedData) const
359 {
360 if (_bSigned) {
361
362 signExtend(iSizeOptimizedData);
363 }
364
365 return base::toPlainInteger(iSizeOptimizedData);
366 }
367
368 // Convert value provided by the user as a string into an int64
convertValueFromString(const string & strValue,int64_t & iData,CParameterAccessContext & parameterAccessContext) const369 bool CIntegerParameterType::convertValueFromString(const string& strValue, int64_t& iData, CParameterAccessContext& parameterAccessContext) const {
370
371 // Reset errno to check if it is updated during the conversion (strtol/strtoul)
372 errno = 0;
373 char *pcStrEnd;
374
375 // Convert the input string
376 if (_bSigned) {
377
378 iData = strtoll(strValue.c_str(), &pcStrEnd, 0);
379 } else {
380
381 iData = strtoull(strValue.c_str(), &pcStrEnd, 0);
382 }
383
384 // Conversion error when the input string does not contain only digits or the number is out of range (int32_t type)
385 if (errno || (*pcStrEnd != '\0')) {
386
387 string strError;
388 strError = "Impossible to convert value " + strValue + " for " + getKind();
389
390 parameterAccessContext.setError(strError);
391
392 return false;
393 }
394
395 return true;
396 }
397
398 // Range checking
checkValueAgainstRange(const string & strValue,type value,type minValue,type maxValue,CParameterAccessContext & parameterAccessContext,bool bHexaValue) const399 template <typename type> bool CIntegerParameterType::checkValueAgainstRange(const string& strValue, type value, type minValue, type maxValue, CParameterAccessContext& parameterAccessContext, bool bHexaValue) const
400 {
401 if (value < minValue || value > maxValue) {
402
403 ostringstream strStream;
404
405 strStream << "Value " << strValue << " standing out of admitted range [";
406
407 if (bHexaValue) {
408
409 // Format Min
410 strStream << "0x" << std::hex << std::uppercase << std::setw(getSize()*2) << std::setfill('0') << makeEncodable(minValue);
411 // Format Max
412 strStream << ", 0x" << std::hex << std::uppercase << std::setw(getSize()*2) << std::setfill('0') << makeEncodable(maxValue);
413
414 } else {
415
416 strStream << minValue << ", " << maxValue;
417 }
418
419 strStream << "] for " << getKind();
420
421 parameterAccessContext.setError(strStream.str());
422
423 return false;
424 }
425 return true;
426 }
427
428 // Adaptation element retrieval
getParameterAdaptation() const429 const CParameterAdaptation* CIntegerParameterType::getParameterAdaptation() const
430 {
431 return static_cast<const CParameterAdaptation*>(findChildOfKind("Adaptation"));
432 }
433
434 // From IXmlSource
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const435 void CIntegerParameterType::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
436 {
437 // Sign
438 xmlElement.setAttributeBoolean("Signed", _bSigned);
439
440 if (_bSigned) {
441
442 // Mininmum
443 xmlElement.setAttributeString("Min", CUtility::toString((int32_t)_uiMin));
444
445 // Maximum
446 xmlElement.setAttributeString("Max", CUtility::toString((int32_t)_uiMax));
447
448 } else {
449
450 // Minimum
451 xmlElement.setAttributeString("Min", CUtility::toString(_uiMin));
452
453 // Maximum
454 xmlElement.setAttributeString("Max", CUtility::toString(_uiMax));
455 }
456
457 // Size
458 xmlElement.setAttributeString("Size", CUtility::toString(getSize() * 8));
459
460 base::toXml(xmlElement, serializingContext);
461
462 }
463