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 45 CEnumParameterType::CEnumParameterType(const string& strName) : base(strName) 46 { 47 } 48 49 string CEnumParameterType::getKind() const 50 { 51 return "EnumParameter"; 52 } 53 54 bool CEnumParameterType::childrenAreDynamic() const 55 { 56 return true; 57 } 58 59 // Element properties 60 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 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) 95 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 162 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 195 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 237 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 248 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) 263 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 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 283 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 303 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 324 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 345 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