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 45 CIntegerParameterType::CIntegerParameterType(const string &strName) : base(strName) 46 { 47 } 48 49 // Kind 50 string CIntegerParameterType::getKind() const 51 { 52 return "IntegerParameter"; 53 } 54 55 // Deal with adaption node 56 bool CIntegerParameterType::childrenAreDynamic() const 57 { 58 return true; 59 } 60 61 // Element properties 62 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 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) 141 bool CIntegerParameterType::toBlackboard(const string &strValue, uint32_t &uiValue, 142 CParameterAccessContext ¶meterAccessContext) 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 183 bool CIntegerParameterType::fromBlackboard(string &strValue, const uint32_t &value, 184 CParameterAccessContext ¶meterAccessContext) 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 221 bool CIntegerParameterType::toBlackboard(uint32_t uiUserValue, uint32_t &uiValue, 222 CParameterAccessContext ¶meterAccessContext) 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 236 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 246 bool CIntegerParameterType::toBlackboard(int32_t iUserValue, uint32_t &uiValue, 247 CParameterAccessContext ¶meterAccessContext) 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 261 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 276 bool CIntegerParameterType::toBlackboard(double dUserValue, uint32_t &uiValue, 277 CParameterAccessContext ¶meterAccessContext) 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 316 bool CIntegerParameterType::fromBlackboard(double &dUserValue, uint32_t uiValue, 317 CParameterAccessContext ¶meterAccessContext) 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) 350 uint32_t CIntegerParameterType::getDefaultValue() const 351 { 352 return _uiMin; 353 } 354 355 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 366 bool CIntegerParameterType::convertValueFromString( 367 const string &strValue, int64_t &iData, CParameterAccessContext ¶meterAccessContext) 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> 400 bool CIntegerParameterType::checkValueAgainstRange(const string &strValue, type value, 401 type minValue, type maxValue, 402 CParameterAccessContext ¶meterAccessContext, 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 435 const CParameterAdaptation *CIntegerParameterType::getParameterAdaptation() const 436 { 437 return static_cast<const CParameterAdaptation *>(findChildOfKind("Adaptation")); 438 } 439 440 // From IXmlSource 441 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