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 235 if ((**string == ACPI_ASCII_ZERO) && 236 (tolower((int)*(*string + 1)) == 'x')) { 237 *string += 2; /* Go past the leading 0x */ 238 return (TRUE); 239 } 240 241 return (FALSE); /* Not a hex string */ 242 } 243 244 /******************************************************************************* 245 * 246 * FUNCTION: acpi_ut_detect_octal_prefix 247 * 248 * PARAMETERS: string - Pointer to input ASCII string 249 * 250 * RETURN: True if an octal "0" prefix was found at the start of the 251 * string 252 * 253 * DESCRIPTION: Detect and remove an octal prefix (zero) 254 * 255 ******************************************************************************/ 256 257 u8 acpi_ut_detect_octal_prefix(char **string) 258 { 259 260 if (**string == ACPI_ASCII_ZERO) { 261 *string += 1; /* Go past the leading 0 */ 262 return (TRUE); 263 } 264 265 return (FALSE); /* Not an octal string */ 266 } 267 268 /******************************************************************************* 269 * 270 * FUNCTION: acpi_ut_insert_digit 271 * 272 * PARAMETERS: accumulated_value - Current value of the integer value 273 * accumulator. The new value is 274 * returned here. 275 * base - Radix, either 8/10/16 276 * ascii_digit - ASCII single digit to be inserted 277 * 278 * RETURN: Status and result of the convert/insert operation. The only 279 * possible returned exception code is numeric overflow of 280 * either the multiply or add conversion operations. 281 * 282 * DESCRIPTION: Generic conversion and insertion function for all bases: 283 * 284 * 1) Multiply the current accumulated/converted value by the 285 * base in order to make room for the new character. 286 * 287 * 2) Convert the new character to binary and add it to the 288 * current accumulated value. 289 * 290 * Note: The only possible exception indicates an integer 291 * overflow (AE_NUMERIC_OVERFLOW) 292 * 293 ******************************************************************************/ 294 295 static acpi_status 296 acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit) 297 { 298 acpi_status status; 299 u64 product; 300 301 /* Make room in the accumulated value for the incoming digit */ 302 303 status = acpi_ut_strtoul_multiply64(*accumulated_value, base, &product); 304 if (ACPI_FAILURE(status)) { 305 return (status); 306 } 307 308 /* Add in the new digit, and store the sum to the accumulated value */ 309 310 status = 311 acpi_ut_strtoul_add64(product, 312 acpi_ut_ascii_char_to_hex(ascii_digit), 313 accumulated_value); 314 315 return (status); 316 } 317 318 /******************************************************************************* 319 * 320 * FUNCTION: acpi_ut_strtoul_multiply64 321 * 322 * PARAMETERS: multiplicand - Current accumulated converted integer 323 * base - Base/Radix 324 * out_product - Where the product is returned 325 * 326 * RETURN: Status and 64-bit product 327 * 328 * DESCRIPTION: Multiply two 64-bit values, with checking for 64-bit overflow as 329 * well as 32-bit overflow if necessary (if the current global 330 * integer width is 32). 331 * 332 ******************************************************************************/ 333 334 static acpi_status 335 acpi_ut_strtoul_multiply64(u64 multiplicand, u32 base, u64 *out_product) 336 { 337 u64 product; 338 u64 quotient; 339 340 /* Exit if either operand is zero */ 341 342 *out_product = 0; 343 if (!multiplicand || !base) { 344 return (AE_OK); 345 } 346 347 /* 348 * Check for 64-bit overflow before the actual multiplication. 349 * 350 * Notes: 64-bit division is often not supported on 32-bit platforms 351 * (it requires a library function), Therefore ACPICA has a local 352 * 64-bit divide function. Also, Multiplier is currently only used 353 * as the radix (8/10/16), to the 64/32 divide will always work. 354 */ 355 acpi_ut_short_divide(ACPI_UINT64_MAX, base, "ient, NULL); 356 if (multiplicand > quotient) { 357 return (AE_NUMERIC_OVERFLOW); 358 } 359 360 product = multiplicand * base; 361 362 /* Check for 32-bit overflow if necessary */ 363 364 if ((acpi_gbl_integer_bit_width == 32) && (product > ACPI_UINT32_MAX)) { 365 return (AE_NUMERIC_OVERFLOW); 366 } 367 368 *out_product = product; 369 return (AE_OK); 370 } 371 372 /******************************************************************************* 373 * 374 * FUNCTION: acpi_ut_strtoul_add64 375 * 376 * PARAMETERS: addend1 - Current accumulated converted integer 377 * digit - New hex value/char 378 * out_sum - Where sum is returned (Accumulator) 379 * 380 * RETURN: Status and 64-bit sum 381 * 382 * DESCRIPTION: Add two 64-bit values, with checking for 64-bit overflow as 383 * well as 32-bit overflow if necessary (if the current global 384 * integer width is 32). 385 * 386 ******************************************************************************/ 387 388 static acpi_status acpi_ut_strtoul_add64(u64 addend1, u32 digit, u64 *out_sum) 389 { 390 u64 sum; 391 392 /* Check for 64-bit overflow before the actual addition */ 393 394 if ((addend1 > 0) && (digit > (ACPI_UINT64_MAX - addend1))) { 395 return (AE_NUMERIC_OVERFLOW); 396 } 397 398 sum = addend1 + digit; 399 400 /* Check for 32-bit overflow if necessary */ 401 402 if ((acpi_gbl_integer_bit_width == 32) && (sum > ACPI_UINT32_MAX)) { 403 return (AE_NUMERIC_OVERFLOW); 404 } 405 406 *out_sum = sum; 407 return (AE_OK); 408 } 409