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