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