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 "EnumParameterType.h"
31 #include <stdlib.h>
32 #include <sstream>
33 #include <iomanip>
34 #include <ctype.h>
35 #include <assert.h>
36 #include "ParameterAccessContext.h"
37 #include "EnumValuePair.h"
38 #include "Utility.h"
39 #include <errno.h>
40 
41 #define base CParameterType
42 
43 using std::string;
44 
CEnumParameterType(const string & strName)45 CEnumParameterType::CEnumParameterType(const string& strName) : base(strName)
46 {
47 }
48 
getKind() const49 string CEnumParameterType::getKind() const
50 {
51     return "EnumParameter";
52 }
53 
childrenAreDynamic() const54 bool CEnumParameterType::childrenAreDynamic() const
55 {
56     return true;
57 }
58 
59 // Element properties
showProperties(string & strResult) const60 void CEnumParameterType::showProperties(string& strResult) const
61 {
62     base::showProperties(strResult);
63 
64     strResult += "Value Pairs:\n";
65 
66     // Show all value pairs
67     size_t uiChild;
68     size_t uiNbChildren = getNbChildren();
69 
70     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
71 
72         const CEnumValuePair* pValuePair = static_cast<const CEnumValuePair*>(getChild(uiChild));
73 
74         strResult += "\tLiteral: \"";
75         strResult += pValuePair->getName();
76         strResult += "\", Numerical: ";
77         strResult += pValuePair->getNumericalAsString();
78         strResult += "\n";
79     }
80 }
81 
fromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)82 bool CEnumParameterType::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
83 {
84     // Size in bits
85     uint32_t uiSizeInBits = xmlElement.getAttributeInteger("Size");
86 
87     // Size
88     setSize(uiSizeInBits / 8);
89 
90     // Base
91     return base::fromXml(xmlElement, serializingContext);
92 }
93 
94 // Conversion (tuning)
toBlackboard(const string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const95 bool CEnumParameterType::toBlackboard(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
96 {
97     int64_t iData;
98 
99     if (isNumber(strValue)) {
100 
101         /// Numerical value provided
102 
103         // Hexa
104         bool bValueProvidedAsHexa = !strValue.compare(0, 2, "0x");
105 
106         errno = 0;
107         char *pcStrEnd;
108 
109         // Get value
110         iData = strtoll(strValue.c_str(), &pcStrEnd, 0);
111 
112         // Conversion error when the input string does not contain any digit or the number is out of range (int32_t type)
113         bool bConversionSucceeded = !errno && (strValue.c_str() != pcStrEnd);
114 
115         // Check validity against type
116         if (!checkValueAgainstRange(strValue, iData, parameterAccessContext, bValueProvidedAsHexa, bConversionSucceeded)) {
117 
118             return false;
119         }
120 
121         if (bValueProvidedAsHexa) {
122 
123             // Sign extend
124             signExtend(iData);
125         }
126 
127         // Check validity against lexical space
128         string strError;
129         if (!isValid(iData, parameterAccessContext)) {
130 
131             parameterAccessContext.setError(strError);
132 
133             return false;
134         }
135     } else {
136         /// Literal value provided
137 
138         // Check validity against lexical space
139         int iNumerical;
140         if (!getNumerical(strValue, iNumerical)) {
141 
142             parameterAccessContext.setError("Provided value not part of lexical space");
143 
144             return false;
145         }
146         iData = iNumerical;
147 
148         // Check validity against type
149         if (!checkValueAgainstRange(strValue, iData, parameterAccessContext, false, isEncodable((uint64_t)iData, true))) {
150 
151             return false;
152         }
153     }
154 
155     // Return data
156     uiValue = (uint32_t)iData;
157 
158     return true;
159 }
160 
161 // Range checking
checkValueAgainstRange(const string & strValue,int64_t value,CParameterAccessContext & parameterAccessContext,bool bHexaValue,bool bConversionSucceeded) const162 bool CEnumParameterType::checkValueAgainstRange(const string& strValue, int64_t value, CParameterAccessContext& parameterAccessContext, bool bHexaValue, bool bConversionSucceeded) const
163 {
164     // Enums are always signed, it means we have one less util bit
165     int64_t maxValue = getMaxValue<uint64_t>();
166     int64_t minValue = -maxValue - 1;
167 
168     if (!bConversionSucceeded || value < minValue || value > maxValue) {
169 
170 	std::ostringstream strStream;
171 
172         strStream << "Value " << strValue << " standing out of admitted range [";
173 
174         if (bHexaValue) {
175 
176             // Format Min
177             strStream << "0x" << std::hex << std::uppercase << std::setw(getSize()*2) << std::setfill('0') << makeEncodable(minValue);
178             // Format Max
179             strStream << ", 0x" << std::hex << std::uppercase << std::setw(getSize()*2) << std::setfill('0') << makeEncodable(maxValue);
180 
181         } else {
182 
183             strStream << minValue << ", " <<  maxValue;
184         }
185 
186         strStream << "] for " << getKind();
187 
188         parameterAccessContext.setError(strStream.str());
189 
190         return false;
191     }
192     return true;
193 }
194 
fromBlackboard(string & strValue,const uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const195 bool CEnumParameterType::fromBlackboard(string& strValue, const uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
196 {
197     // Take care of format
198     if (parameterAccessContext.valueSpaceIsRaw()) {
199 
200         // Format
201 	std::ostringstream strStream;
202 
203         // Numerical format requested
204         if (parameterAccessContext.outputRawFormatIsHex()) {
205 
206             // Hexa display with unecessary bits cleared out
207             strStream << "0x" << std::hex << std::uppercase << std::setw(getSize()*2) << std::setfill('0') << makeEncodable(uiValue);
208 
209             strValue = strStream.str();
210         } else {
211 
212             // Integer display
213             int32_t iValue = uiValue;
214 
215             // Sign extend
216             signExtend(iValue);
217 
218             strStream << iValue;
219 
220             strValue = strStream.str();
221         }
222     } else {
223 
224         // Integer display
225         int32_t iValue = uiValue;
226 
227         // Sign extend
228         signExtend(iValue);
229 
230         // Literal display requested (should succeed)
231         getLiteral(iValue, strValue);
232     }
233     return true;
234 }
235 
236 // Value access
toBlackboard(int32_t iUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const237 bool CEnumParameterType::toBlackboard(int32_t iUserValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
238 {
239     if (!isValid(iUserValue, parameterAccessContext)) {
240 
241         return false;
242     }
243     uiValue = iUserValue;
244 
245     return true;
246 }
247 
fromBlackboard(int32_t & iUserValue,uint32_t uiValue,CParameterAccessContext & parameterAccessContext) const248 bool CEnumParameterType::fromBlackboard(int32_t& iUserValue, uint32_t uiValue, CParameterAccessContext& parameterAccessContext) const
249 {
250     (void)parameterAccessContext;
251 
252     int32_t iValue = uiValue;
253 
254     // Sign extend
255     signExtend(iValue);
256 
257     iUserValue = iValue;
258 
259     return true;
260 }
261 
262 // Default value handling (simulation only)
getDefaultValue() const263 uint32_t CEnumParameterType::getDefaultValue() const
264 {
265     if (!getNbChildren()) {
266 
267         return 0;
268     }
269 
270     // Return first available numerical
271     return static_cast<const CEnumValuePair*>(getChild(0))->getNumerical();
272 }
273 
274 // Check string is a number
isNumber(const string & strValue)275 bool CEnumParameterType::isNumber(const string& strValue)
276 {
277     char cFirst = strValue[0];
278 
279     return isdigit(cFirst) || cFirst == '+' || cFirst == '-';
280 }
281 
282 // Literal - numerical conversions
getLiteral(int32_t iNumerical,string & strLiteral) const283 bool CEnumParameterType::getLiteral(int32_t iNumerical, string& strLiteral) const
284 {
285     size_t uiChild;
286     size_t uiNbChildren = getNbChildren();
287 
288     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
289 
290         const CEnumValuePair* pValuePair = static_cast<const CEnumValuePair*>(getChild(uiChild));
291 
292         if (pValuePair->getNumerical() == iNumerical) {
293 
294             strLiteral = pValuePair->getName();
295 
296             return true;
297         }
298     }
299 
300     return false;
301 }
302 
getNumerical(const string & strLiteral,int & iNumerical) const303 bool CEnumParameterType::getNumerical(const string& strLiteral, int& iNumerical) const
304 {
305     size_t uiChild;
306     size_t uiNbChildren = getNbChildren();
307 
308     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
309 
310         const CEnumValuePair* pValuePair = static_cast<const CEnumValuePair*>(getChild(uiChild));
311 
312         if (pValuePair->getName() == strLiteral) {
313 
314             iNumerical = pValuePair->getNumerical();
315 
316             return true;
317         }
318     }
319 
320     return false;
321 }
322 
323 // Numerical validity of the enum value
isValid(int iNumerical,CParameterAccessContext & parameterAccessContext) const324 bool CEnumParameterType::isValid(int iNumerical, CParameterAccessContext& parameterAccessContext) const
325 {
326     // Check that the value is part of the allowed values for this kind of enum
327     size_t uiChild;
328     size_t uiNbChildren = getNbChildren();
329 
330     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
331 
332         const CEnumValuePair* pValuePair = static_cast<const CEnumValuePair*>(getChild(uiChild));
333 
334         if (pValuePair->getNumerical() == iNumerical) {
335 
336             return true;
337         }
338     }
339 
340     parameterAccessContext.setError("Provided value not part of numerical space");
341 
342     return false;
343 }
344 // From IXmlSource
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const345 void CEnumParameterType::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
346 {
347     // Size
348     xmlElement.setAttributeString("Size", CUtility::toString(getSize() * 8));
349 
350     base::toXml(xmlElement, serializingContext);
351 }
352