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)
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 ? std::to_string((int32_t)_uiMin) : std::to_string(_uiMin);
74 strResult += "\n";
75
76 // Max
77 strResult += "Max: ";
78 strResult += _bSigned ? std::to_string((int32_t)_uiMax) : std::to_string(_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,
94 CXmlSerializingContext &serializingContext)
95 {
96 // Sign
97 xmlElement.getAttribute("Signed", _bSigned);
98
99 // Size in bits
100 size_t sizeInBits = 0;
101 xmlElement.getAttribute("Size", sizeInBits);
102
103 // Size
104 setSize(sizeInBits / 8);
105
106 // Min / Max
107 // TODO: Make IntegerParameter template
108 if (_bSigned) {
109
110 // Signed means we have one less util bit
111 sizeInBits--;
112
113 if (!xmlElement.getAttribute("Min", (int32_t &)_uiMin)) {
114
115 _uiMin = 1U << sizeInBits;
116 }
117
118 if (!xmlElement.getAttribute("Max", (int32_t &)_uiMax)) {
119
120 _uiMax = (1U << sizeInBits) - 1;
121 }
122 signExtend((int32_t &)_uiMin);
123 signExtend((int32_t &)_uiMax);
124 } else {
125 if (!xmlElement.getAttribute("Min", _uiMin)) {
126
127 _uiMin = 0;
128 }
129
130 if (!xmlElement.getAttribute("Max", _uiMax)) {
131
132 _uiMax = ~0U >> (8 * sizeof(size_t) - sizeInBits);
133 }
134 }
135
136 // Base
137 return base::fromXml(xmlElement, serializingContext);
138 }
139
140 // Conversion (tuning)
toBlackboard(const string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const141 bool CIntegerParameterType::toBlackboard(const string &strValue, uint32_t &uiValue,
142 CParameterAccessContext ¶meterAccessContext) const
143 {
144 // Hexa
145 bool bValueProvidedAsHexa = utility::isHexadecimal(strValue);
146
147 // Get integer value from the string provided
148 int64_t iData;
149
150 if (!convertValueFromString(strValue, iData, parameterAccessContext)) {
151
152 return false;
153 }
154
155 // Check against Min / Max
156 if (_bSigned) {
157
158 if (bValueProvidedAsHexa && isEncodable((uint64_t)iData, !bValueProvidedAsHexa)) {
159
160 // Sign extend
161 signExtend(iData);
162 }
163
164 if (!checkValueAgainstRange<int64_t>(strValue, iData, (int32_t)_uiMin, (int32_t)_uiMax,
165 parameterAccessContext, bValueProvidedAsHexa)) {
166
167 return false;
168 }
169 } else {
170
171 if (!checkValueAgainstRange<uint64_t>(strValue, iData, _uiMin, _uiMax,
172 parameterAccessContext, bValueProvidedAsHexa)) {
173
174 return false;
175 }
176 }
177
178 uiValue = (uint32_t)iData;
179
180 return true;
181 }
182
fromBlackboard(string & strValue,const uint32_t & value,CParameterAccessContext & parameterAccessContext) const183 bool CIntegerParameterType::fromBlackboard(string &strValue, const uint32_t &value,
184 CParameterAccessContext ¶meterAccessContext) const
185 {
186 // Check unsigned value is encodable
187 assert(isEncodable(value, false));
188
189 // Format
190 ostringstream stream;
191
192 // Take care of format
193 if (parameterAccessContext.valueSpaceIsRaw() && parameterAccessContext.outputRawFormatIsHex()) {
194
195 // Hexa display with unecessary bits cleared out
196 stream << "0x" << std::hex << std::uppercase << std::setw(static_cast<int>(getSize() * 2))
197 << std::setfill('0') << value;
198 } else {
199
200 if (_bSigned) {
201
202 int32_t iValue = value;
203
204 // Sign extend
205 signExtend(iValue);
206
207 stream << iValue;
208 } else {
209
210 stream << value;
211 }
212 }
213
214 strValue = stream.str();
215
216 return true;
217 }
218
219 // Value access
220 // Integer
toBlackboard(uint32_t uiUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const221 bool CIntegerParameterType::toBlackboard(uint32_t uiUserValue, uint32_t &uiValue,
222 CParameterAccessContext ¶meterAccessContext) const
223 {
224 if (uiUserValue < _uiMin || uiUserValue > _uiMax) {
225
226 parameterAccessContext.setError("Value out of range");
227
228 return false;
229 }
230 // Do assign
231 uiValue = uiUserValue;
232
233 return true;
234 }
235
fromBlackboard(uint32_t & uiUserValue,uint32_t uiValue,CParameterAccessContext &) const236 bool CIntegerParameterType::fromBlackboard(uint32_t &uiUserValue, uint32_t uiValue,
237 CParameterAccessContext & /*ctx*/) const
238 {
239 // Do assign
240 uiUserValue = uiValue;
241
242 return true;
243 }
244
245 // Signed Integer
toBlackboard(int32_t iUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const246 bool CIntegerParameterType::toBlackboard(int32_t iUserValue, uint32_t &uiValue,
247 CParameterAccessContext ¶meterAccessContext) const
248 {
249 if (iUserValue < (int32_t)_uiMin || iUserValue > (int32_t)_uiMax) {
250
251 parameterAccessContext.setError("Value out of range");
252
253 return false;
254 }
255 // Do assign
256 uiValue = iUserValue;
257
258 return true;
259 }
260
fromBlackboard(int32_t & iUserValue,uint32_t uiValue,CParameterAccessContext &) const261 bool CIntegerParameterType::fromBlackboard(int32_t &iUserValue, uint32_t uiValue,
262 CParameterAccessContext & /*ctx*/) const
263 {
264 int32_t iValue = uiValue;
265
266 // Sign extend
267 signExtend(iValue);
268
269 // Do assign
270 iUserValue = iValue;
271
272 return true;
273 }
274
275 // Double
toBlackboard(double dUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const276 bool CIntegerParameterType::toBlackboard(double dUserValue, uint32_t &uiValue,
277 CParameterAccessContext ¶meterAccessContext) const
278 {
279 // Check if there's an adaptation object available
280 const CParameterAdaptation *pParameterAdaption = getParameterAdaptation();
281
282 if (!pParameterAdaption) {
283
284 // Reject request and let upper class handle the error
285 return base::toBlackboard(dUserValue, uiValue, parameterAccessContext);
286 }
287
288 // Do the conversion
289 int64_t iConvertedValue = pParameterAdaption->fromUserValue(dUserValue);
290
291 // Check against range
292 if (_bSigned) {
293
294 if (iConvertedValue < (int32_t)_uiMin || iConvertedValue > (int32_t)_uiMax) {
295
296 parameterAccessContext.setError("Value out of range");
297
298 return false;
299 }
300 } else {
301
302 if (iConvertedValue < _uiMin || iConvertedValue > _uiMax) {
303
304 parameterAccessContext.setError("Value out of range");
305
306 return false;
307 }
308 }
309
310 // Do assign
311 uiValue = (uint32_t)iConvertedValue;
312
313 return true;
314 }
315
fromBlackboard(double & dUserValue,uint32_t uiValue,CParameterAccessContext & parameterAccessContext) const316 bool CIntegerParameterType::fromBlackboard(double &dUserValue, uint32_t uiValue,
317 CParameterAccessContext ¶meterAccessContext) const
318 {
319 // Check if there's an adaptation object available
320 const CParameterAdaptation *pParameterAdaption = getParameterAdaptation();
321
322 if (!pParameterAdaption) {
323
324 // Reject request and let upper class handle the error
325 return base::fromBlackboard(dUserValue, uiValue, parameterAccessContext);
326 }
327
328 int64_t iValueToConvert;
329
330 // Deal with signed data
331 if (_bSigned) {
332
333 int32_t iValue = uiValue;
334
335 signExtend(iValue);
336
337 iValueToConvert = iValue;
338 } else {
339
340 iValueToConvert = uiValue;
341 }
342
343 // Do the conversion
344 dUserValue = pParameterAdaption->toUserValue(iValueToConvert);
345
346 return true;
347 }
348
349 // Default value handling (simulation only)
getDefaultValue() const350 uint32_t CIntegerParameterType::getDefaultValue() const
351 {
352 return _uiMin;
353 }
354
toPlainInteger(int iSizeOptimizedData) const355 int CIntegerParameterType::toPlainInteger(int iSizeOptimizedData) const
356 {
357 if (_bSigned) {
358
359 signExtend(iSizeOptimizedData);
360 }
361
362 return base::toPlainInteger(iSizeOptimizedData);
363 }
364
365 // Convert value provided by the user as a string into an int64
convertValueFromString(const string & strValue,int64_t & iData,CParameterAccessContext & parameterAccessContext) const366 bool CIntegerParameterType::convertValueFromString(
367 const string &strValue, int64_t &iData, CParameterAccessContext ¶meterAccessContext) const
368 {
369
370 // Reset errno to check if it is updated during the conversion (strtol/strtoul)
371 errno = 0;
372 char *pcStrEnd;
373
374 // Convert the input string
375 if (_bSigned) {
376
377 iData = strtoll(strValue.c_str(), &pcStrEnd, 0);
378 } else {
379
380 iData = strtoull(strValue.c_str(), &pcStrEnd, 0);
381 }
382
383 // Conversion error when the input string does not contain only digits or the number is out of
384 // 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
399 template <typename type>
checkValueAgainstRange(const string & strValue,type value,type minValue,type maxValue,CParameterAccessContext & parameterAccessContext,bool bHexaValue) const400 bool CIntegerParameterType::checkValueAgainstRange(const string &strValue, type value,
401 type minValue, type maxValue,
402 CParameterAccessContext ¶meterAccessContext,
403 bool bHexaValue) const
404 {
405 if (value < minValue || value > maxValue) {
406
407 ostringstream stream;
408
409 stream << "Value " << strValue << " standing out of admitted range [";
410
411 if (bHexaValue) {
412
413 stream << "0x" << std::hex << std::uppercase
414 << std::setw(static_cast<int>(getSize() * 2)) << std::setfill('0');
415 // Format Min
416 stream << minValue;
417 // Format Max
418 stream << maxValue;
419
420 } else {
421
422 stream << minValue << ", " << maxValue;
423 }
424
425 stream << "] for " << getKind();
426
427 parameterAccessContext.setError(stream.str());
428
429 return false;
430 }
431 return true;
432 }
433
434 // Adaptation element retrieval
getParameterAdaptation() const435 const CParameterAdaptation *CIntegerParameterType::getParameterAdaptation() const
436 {
437 return static_cast<const CParameterAdaptation *>(findChildOfKind("Adaptation"));
438 }
439
440 // From IXmlSource
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const441 void CIntegerParameterType::toXml(CXmlElement &xmlElement,
442 CXmlSerializingContext &serializingContext) const
443 {
444 // Sign
445 xmlElement.setAttribute("Signed", _bSigned);
446
447 if (_bSigned) {
448
449 // Mininmum
450 xmlElement.setAttribute("Min", (int32_t)_uiMin);
451
452 // Maximum
453 xmlElement.setAttribute("Max", (int32_t)_uiMax);
454
455 } else {
456
457 // Minimum
458 xmlElement.setAttribute("Min", _uiMin);
459
460 // Maximum
461 xmlElement.setAttribute("Max", _uiMax);
462 }
463
464 // Size
465 xmlElement.setAttribute("Size", getSize() * 8);
466
467 base::toXml(xmlElement, serializingContext);
468 }
469