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 "EnumValuePair.h"
32 #include "ParameterAccessContext.h"
33 #include "convert.hpp"
34 
35 #define base CParameterType
36 
37 using std::string;
38 
CEnumParameterType(const string & strName)39 CEnumParameterType::CEnumParameterType(const string &strName) : base(strName)
40 {
41 }
42 
getKind() const43 string CEnumParameterType::getKind() const
44 {
45     return "EnumParameter";
46 }
47 
childrenAreDynamic() const48 bool CEnumParameterType::childrenAreDynamic() const
49 {
50     return true;
51 }
52 
53 // Element properties
showProperties(string & strResult) const54 void CEnumParameterType::showProperties(string &strResult) const
55 {
56     base::showProperties(strResult);
57 
58     strResult += "Value Pairs:\n";
59 
60     // Show all value pairs
61     size_t uiChild;
62     size_t uiNbChildren = getNbChildren();
63 
64     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
65 
66         const CEnumValuePair *pValuePair = static_cast<const CEnumValuePair *>(getChild(uiChild));
67 
68         strResult += "\tLiteral: \"";
69         strResult += pValuePair->getName();
70         strResult += "\", Numerical: ";
71         strResult += pValuePair->getNumericalAsString();
72         strResult += "\n";
73     }
74 }
75 
fromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)76 bool CEnumParameterType::fromXml(const CXmlElement &xmlElement,
77                                  CXmlSerializingContext &serializingContext)
78 {
79     // Size in bits
80     size_t sizeInBits = 0;
81     if (not xmlElement.getAttribute("Size", sizeInBits)) {
82         return false;
83     }
84 
85     // Size
86     setSize(sizeInBits / 8);
87 
88     // Base
89     return base::fromXml(xmlElement, serializingContext);
90 }
91 
92 // Conversion (tuning)
toBlackboard(const string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const93 bool CEnumParameterType::toBlackboard(const string &strValue, uint32_t &uiValue,
94                                       CParameterAccessContext &parameterAccessContext) const
95 {
96     int32_t iParsedUserValue = 0;
97 
98     // Try to read the user-provided string as an integer
99     if (not convertTo(strValue, iParsedUserValue)) {
100         // If it fails to parse as an integer, first try to convert it from
101         // lexical to numerical space.
102         int32_t iNumerical;
103         if (not getNumerical(strValue, iNumerical)) {
104 
105             parameterAccessContext.setError("Provided value '" + strValue +
106                                             "' is not part of the lexical space"
107                                             " or not within the numerical range.");
108 
109             return false;
110         }
111         iParsedUserValue = iNumerical;
112     }
113 
114     // Once it has been converted to a number (either through parsing or
115     // through lexical->numerical conversion), call the numerical overload of
116     // toBlackboard.
117     return toBlackboard(iParsedUserValue, uiValue, parameterAccessContext);
118 }
119 
getMin() const120 int32_t CEnumParameterType::getMin() const
121 {
122     // Enums are always signed, it means we have one less util bit
123     return -getMax() - 1;
124 }
125 
getMax() const126 int32_t CEnumParameterType::getMax() const
127 {
128     return getMaxValue<int32_t>();
129 }
130 
fromBlackboard(string & userValue,const uint32_t & value,CParameterAccessContext &) const131 bool CEnumParameterType::fromBlackboard(string &userValue, const uint32_t &value,
132                                         CParameterAccessContext & /*ctx*/) const
133 {
134     // Convert the raw value from the blackboard
135     int32_t signedValue = static_cast<int32_t>(value);
136     signExtend(signedValue);
137 
138     // Convert from numerical space to literal space
139     return getLiteral(signedValue, userValue);
140 }
141 
142 // Value access
toBlackboard(int32_t userValue,uint32_t & value,CParameterAccessContext & parameterAccessContext) const143 bool CEnumParameterType::toBlackboard(int32_t userValue, uint32_t &value,
144                                       CParameterAccessContext &parameterAccessContext) const
145 {
146     if (!checkValueAgainstSpace(userValue)) {
147 
148         parameterAccessContext.setError(std::to_string(userValue) +
149                                         " is not part of numerical space.");
150 
151         return false;
152     }
153 
154     if (userValue < getMin() or userValue > getMax()) {
155 
156         // FIXME: values provided as hexa (either on command line or in a config
157         // file will appear in decimal base instead of hexa base...
158         parameterAccessContext.setError(
159             "Value " + std::to_string(userValue) + " standing out of admitted range [" +
160             std::to_string(getMin()) + ", " + std::to_string(getMax()) + "] for " + getKind());
161         return false;
162     }
163 
164     value = static_cast<uint32_t>(userValue);
165 
166     return true;
167 }
168 
fromBlackboard(int32_t & userValue,uint32_t value,CParameterAccessContext &) const169 bool CEnumParameterType::fromBlackboard(int32_t &userValue, uint32_t value,
170                                         CParameterAccessContext & /*ctx*/) const
171 {
172     int32_t signedValue = static_cast<int32_t>(value);
173 
174     // Sign extend
175     signExtend(signedValue);
176 
177     userValue = signedValue;
178 
179     return true;
180 }
181 
182 // Default value handling (simulation only)
getDefaultValue() const183 uint32_t CEnumParameterType::getDefaultValue() const
184 {
185     if (!getNbChildren()) {
186 
187         return 0;
188     }
189 
190     // Return first available numerical
191     return static_cast<const CEnumValuePair *>(getChild(0))->getNumerical();
192 }
193 
194 // Literal - numerical conversions
getLiteral(int32_t iNumerical,string & strLiteral) const195 bool CEnumParameterType::getLiteral(int32_t iNumerical, string &strLiteral) const
196 {
197     size_t uiChild;
198     size_t uiNbChildren = getNbChildren();
199 
200     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
201 
202         const CEnumValuePair *pValuePair = static_cast<const CEnumValuePair *>(getChild(uiChild));
203 
204         if (pValuePair->getNumerical() == iNumerical) {
205 
206             strLiteral = pValuePair->getName();
207 
208             return true;
209         }
210     }
211 
212     return false;
213 }
214 
getNumerical(const string & strLiteral,int32_t & iNumerical) const215 bool CEnumParameterType::getNumerical(const string &strLiteral, int32_t &iNumerical) const
216 {
217     size_t uiChild;
218     size_t uiNbChildren = getNbChildren();
219 
220     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
221 
222         const CEnumValuePair *pValuePair = static_cast<const CEnumValuePair *>(getChild(uiChild));
223 
224         if (pValuePair->getName() == strLiteral) {
225 
226             iNumerical = pValuePair->getNumerical();
227 
228             return true;
229         }
230     }
231 
232     return false;
233 }
234 
235 // Numerical validity of the enum value
checkValueAgainstSpace(int32_t iNumerical) const236 bool CEnumParameterType::checkValueAgainstSpace(int32_t iNumerical) const
237 {
238     // Check that the value is part of the allowed values for this kind of enum
239     size_t uiChild;
240     size_t uiNbChildren = getNbChildren();
241 
242     for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
243 
244         const CEnumValuePair *pValuePair = static_cast<const CEnumValuePair *>(getChild(uiChild));
245 
246         if (pValuePair->getNumerical() == iNumerical) {
247 
248             return true;
249         }
250     }
251 
252     return false;
253 }
254 
255 // From IXmlSource
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const256 void CEnumParameterType::toXml(CXmlElement &xmlElement,
257                                CXmlSerializingContext &serializingContext) const
258 {
259     // Size
260     xmlElement.setAttribute("Size", getSize() * 8);
261 
262     base::toXml(xmlElement, serializingContext);
263 }
264