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 &parameterAccessContext) 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 &parameterAccessContext) 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 &parameterAccessContext) 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 &parameterAccessContext) 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 &parameterAccessContext) 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 &parameterAccessContext) 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 &parameterAccessContext) 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 &parameterAccessContext,
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