1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /******************************************************************************* 3 * 4 * Module Name: utstrsuppt - Support functions for string-to-integer conversion 5 * 6 ******************************************************************************/ 7 8 #include <acpi/acpi.h> 9 #include "accommon.h" 10 11 #define _COMPONENT ACPI_UTILITIES 12 ACPI_MODULE_NAME("utstrsuppt") 13 14 /* Local prototypes */ 15 static acpi_status 16 acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit); 17 18 static acpi_status 19 acpi_ut_strtoul_multiply64(u64 multiplicand, u32 base, u64 *out_product); 20 21 static acpi_status acpi_ut_strtoul_add64(u64 addend1, u32 digit, u64 *out_sum); 22 23 /******************************************************************************* 24 * 25 * FUNCTION: acpi_ut_convert_octal_string 26 * 27 * PARAMETERS: string - Null terminated input string 28 * return_value_ptr - Where the converted value is returned 29 * 30 * RETURN: Status and 64-bit converted integer 31 * 32 * DESCRIPTION: Performs a base 8 conversion of the input string to an 33 * integer value, either 32 or 64 bits. 34 * 35 * NOTE: Maximum 64-bit unsigned octal value is 01777777777777777777777 36 * Maximum 32-bit unsigned octal value is 037777777777 37 * 38 ******************************************************************************/ 39 40 acpi_status acpi_ut_convert_octal_string(char *string, u64 *return_value_ptr) 41 { 42 u64 accumulated_value = 0; 43 acpi_status status = AE_OK; 44 45 /* Convert each ASCII byte in the input string */ 46 47 while (*string) { 48 49 /* Character must be ASCII 0-7, otherwise terminate with no error */ 50 51 if (!(ACPI_IS_OCTAL_DIGIT(*string))) { 52 break; 53 } 54 55 /* Convert and insert this octal digit into the accumulator */ 56 57 status = acpi_ut_insert_digit(&accumulated_value, 8, *string); 58 if (ACPI_FAILURE(status)) { 59 status = AE_OCTAL_OVERFLOW; 60 break; 61 } 62 63 string++; 64 } 65 66 /* Always return the value that has been accumulated */ 67 68 *return_value_ptr = accumulated_value; 69 return (status); 70 } 71 72 /******************************************************************************* 73 * 74 * FUNCTION: acpi_ut_convert_decimal_string 75 * 76 * PARAMETERS: string - Null terminated input string 77 * return_value_ptr - Where the converted value is returned 78 * 79 * RETURN: Status and 64-bit converted integer 80 * 81 * DESCRIPTION: Performs a base 10 conversion of the input string to an 82 * integer value, either 32 or 64 bits. 83 * 84 * NOTE: Maximum 64-bit unsigned decimal value is 18446744073709551615 85 * Maximum 32-bit unsigned decimal value is 4294967295 86 * 87 ******************************************************************************/ 88 89 acpi_status acpi_ut_convert_decimal_string(char *string, u64 *return_value_ptr) 90 { 91 u64 accumulated_value = 0; 92 acpi_status status = AE_OK; 93 94 /* Convert each ASCII byte in the input string */ 95 96 while (*string) { 97 98 /* Character must be ASCII 0-9, otherwise terminate with no error */ 99 100 if (!isdigit(*string)) { 101 break; 102 } 103 104 /* Convert and insert this decimal digit into the accumulator */ 105 106 status = acpi_ut_insert_digit(&accumulated_value, 10, *string); 107 if (ACPI_FAILURE(status)) { 108 status = AE_DECIMAL_OVERFLOW; 109 break; 110 } 111 112 string++; 113 } 114 115 /* Always return the value that has been accumulated */ 116 117 *return_value_ptr = accumulated_value; 118 return (status); 119 } 120 121 /******************************************************************************* 122 * 123 * FUNCTION: acpi_ut_convert_hex_string 124 * 125 * PARAMETERS: string - Null terminated input string 126 * return_value_ptr - Where the converted value is returned 127 * 128 * RETURN: Status and 64-bit converted integer 129 * 130 * DESCRIPTION: Performs a base 16 conversion of the input string to an 131 * integer value, either 32 or 64 bits. 132 * 133 * NOTE: Maximum 64-bit unsigned hex value is 0xFFFFFFFFFFFFFFFF 134 * Maximum 32-bit unsigned hex value is 0xFFFFFFFF 135 * 136 ******************************************************************************/ 137 138 acpi_status acpi_ut_convert_hex_string(char *string, u64 *return_value_ptr) 139 { 140 u64 accumulated_value = 0; 141 acpi_status status = AE_OK; 142 143 /* Convert each ASCII byte in the input string */ 144 145 while (*string) { 146 147 /* Must be ASCII A-F, a-f, or 0-9, otherwise terminate with no error */ 148 149 if (!isxdigit(*string)) { 150 break; 151 } 152 153 /* Convert and insert this hex digit into the accumulator */ 154 155 status = acpi_ut_insert_digit(&accumulated_value, 16, *string); 156 if (ACPI_FAILURE(status)) { 157 status = AE_HEX_OVERFLOW; 158 break; 159 } 160 161 string++; 162 } 163 164 /* Always return the value that has been accumulated */ 165 166 *return_value_ptr = accumulated_value; 167 return (status); 168 } 169 170 /******************************************************************************* 171 * 172 * FUNCTION: acpi_ut_remove_leading_zeros 173 * 174 * PARAMETERS: string - Pointer to input ASCII string 175 * 176 * RETURN: Next character after any leading zeros. This character may be 177 * used by the caller to detect end-of-string. 178 * 179 * DESCRIPTION: Remove any leading zeros in the input string. Return the 180 * next character after the final ASCII zero to enable the caller 181 * to check for the end of the string (NULL terminator). 182 * 183 ******************************************************************************/ 184 185 char acpi_ut_remove_leading_zeros(char **string) 186 { 187 188 while (**string == ACPI_ASCII_ZERO) { 189 *string += 1; 190 } 191 192 return (**string); 193 } 194 195 /******************************************************************************* 196 * 197 * FUNCTION: acpi_ut_remove_whitespace 198 * 199 * PARAMETERS: string - Pointer to input ASCII string 200 * 201 * RETURN: Next character after any whitespace. This character may be 202 * used by the caller to detect end-of-string. 203 * 204 * DESCRIPTION: Remove any leading whitespace in the input string. Return the 205 * next character after the final ASCII zero to enable the caller 206 * to check for the end of the string (NULL terminator). 207 * 208 ******************************************************************************/ 209 210 char acpi_ut_remove_whitespace(char **string) 211 { 212 213 while (isspace((u8)**string)) { 214 *string += 1; 215 } 216 217 return (**string); 218 } 219 220 /******************************************************************************* 221 * 222 * FUNCTION: acpi_ut_detect_hex_prefix 223 * 224 * PARAMETERS: string - Pointer to input ASCII string 225 * 226 * RETURN: TRUE if a "0x" prefix was found at the start of the string 227 * 228 * DESCRIPTION: Detect and remove a hex "0x" prefix 229 * 230 ******************************************************************************/ 231 232 u8 acpi_ut_detect_hex_prefix(char **string) 233 { 234 char *initial_position = *string; 235 236 acpi_ut_remove_hex_prefix(string); 237 if (*string != initial_position) { 238 return (TRUE); /* String is past leading 0x */ 239 } 240 241 return (FALSE); /* Not a hex string */ 242 } 243 244 /******************************************************************************* 245 * 246 * FUNCTION: acpi_ut_remove_hex_prefix 247 * 248 * PARAMETERS: string - Pointer to input ASCII string 249 * 250 * RETURN: none 251 * 252 * DESCRIPTION: Remove a hex "0x" prefix 253 * 254 ******************************************************************************/ 255 256 void acpi_ut_remove_hex_prefix(char **string) 257 { 258 if ((**string == ACPI_ASCII_ZERO) && 259 (tolower((int)*(*string + 1)) == 'x')) { 260 *string += 2; /* Go past the leading 0x */ 261 } 262 } 263 264 /******************************************************************************* 265 * 266 * FUNCTION: acpi_ut_detect_octal_prefix 267 * 268 * PARAMETERS: string - Pointer to input ASCII string 269 * 270 * RETURN: True if an octal "0" prefix was found at the start of the 271 * string 272 * 273 * DESCRIPTION: Detect and remove an octal prefix (zero) 274 * 275 ******************************************************************************/ 276 277 u8 acpi_ut_detect_octal_prefix(char **string) 278 { 279 280 if (**string == ACPI_ASCII_ZERO) { 281 *string += 1; /* Go past the leading 0 */ 282 return (TRUE); 283 } 284 285 return (FALSE); /* Not an octal string */ 286 } 287 288 /******************************************************************************* 289 * 290 * FUNCTION: acpi_ut_insert_digit 291 * 292 * PARAMETERS: accumulated_value - Current value of the integer value 293 * accumulator. The new value is 294 * returned here. 295 * base - Radix, either 8/10/16 296 * ascii_digit - ASCII single digit to be inserted 297 * 298 * RETURN: Status and result of the convert/insert operation. The only 299 * possible returned exception code is numeric overflow of 300 * either the multiply or add conversion operations. 301 * 302 * DESCRIPTION: Generic conversion and insertion function for all bases: 303 * 304 * 1) Multiply the current accumulated/converted value by the 305 * base in order to make room for the new character. 306 * 307 * 2) Convert the new character to binary and add it to the 308 * current accumulated value. 309 * 310 * Note: The only possible exception indicates an integer 311 * overflow (AE_NUMERIC_OVERFLOW) 312 * 313 ******************************************************************************/ 314 315 static acpi_status 316 acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit) 317 { 318 acpi_status status; 319 u64 product; 320 321 /* Make room in the accumulated value for the incoming digit */ 322 323 status = acpi_ut_strtoul_multiply64(*accumulated_value, base, &product); 324 if (ACPI_FAILURE(status)) { 325 return (status); 326 } 327 328 /* Add in the new digit, and store the sum to the accumulated value */ 329 330 status = 331 acpi_ut_strtoul_add64(product, 332 acpi_ut_ascii_char_to_hex(ascii_digit), 333 accumulated_value); 334 335 return (status); 336 } 337 338 /******************************************************************************* 339 * 340 * FUNCTION: acpi_ut_strtoul_multiply64 341 * 342 * PARAMETERS: multiplicand - Current accumulated converted integer 343 * base - Base/Radix 344 * out_product - Where the product is returned 345 * 346 * RETURN: Status and 64-bit product 347 * 348 * DESCRIPTION: Multiply two 64-bit values, with checking for 64-bit overflow as 349 * well as 32-bit overflow if necessary (if the current global 350 * integer width is 32). 351 * 352 ******************************************************************************/ 353 354 static acpi_status 355 acpi_ut_strtoul_multiply64(u64 multiplicand, u32 base, u64 *out_product) 356 { 357 u64 product; 358 u64 quotient; 359 360 /* Exit if either operand is zero */ 361 362 *out_product = 0; 363 if (!multiplicand || !base) { 364 return (AE_OK); 365 } 366 367 /* 368 * Check for 64-bit overflow before the actual multiplication. 369 * 370 * Notes: 64-bit division is often not supported on 32-bit platforms 371 * (it requires a library function), Therefore ACPICA has a local 372 * 64-bit divide function. Also, Multiplier is currently only used 373 * as the radix (8/10/16), to the 64/32 divide will always work. 374 */ 375 acpi_ut_short_divide(ACPI_UINT64_MAX, base, "ient, NULL); 376 if (multiplicand > quotient) { 377 return (AE_NUMERIC_OVERFLOW); 378 } 379 380 product = multiplicand * base; 381 382 /* Check for 32-bit overflow if necessary */ 383 384 if ((acpi_gbl_integer_bit_width == 32) && (product > ACPI_UINT32_MAX)) { 385 return (AE_NUMERIC_OVERFLOW); 386 } 387 388 *out_product = product; 389 return (AE_OK); 390 } 391 392 /******************************************************************************* 393 * 394 * FUNCTION: acpi_ut_strtoul_add64 395 * 396 * PARAMETERS: addend1 - Current accumulated converted integer 397 * digit - New hex value/char 398 * out_sum - Where sum is returned (Accumulator) 399 * 400 * RETURN: Status and 64-bit sum 401 * 402 * DESCRIPTION: Add two 64-bit values, with checking for 64-bit overflow as 403 * well as 32-bit overflow if necessary (if the current global 404 * integer width is 32). 405 * 406 ******************************************************************************/ 407 408 static acpi_status acpi_ut_strtoul_add64(u64 addend1, u32 digit, u64 *out_sum) 409 { 410 u64 sum; 411 412 /* Check for 64-bit overflow before the actual addition */ 413 414 if ((addend1 > 0) && (digit > (ACPI_UINT64_MAX - addend1))) { 415 return (AE_NUMERIC_OVERFLOW); 416 } 417 418 sum = addend1 + digit; 419 420 /* Check for 32-bit overflow if necessary */ 421 422 if ((acpi_gbl_integer_bit_width == 32) && (sum > ACPI_UINT32_MAX)) { 423 return (AE_NUMERIC_OVERFLOW); 424 } 425 426 *out_sum = sum; 427 return (AE_OK); 428 } 429