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  
acpi_ut_convert_octal_string(char * string,u64 * return_value_ptr)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, 8, *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  
acpi_ut_convert_decimal_string(char * string,u64 * return_value_ptr)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((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, 10, *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  
acpi_ut_convert_hex_string(char * string,u64 * return_value_ptr)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, 16, *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  
acpi_ut_remove_leading_zeros(char ** string)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  
acpi_ut_remove_whitespace(char ** string)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  
acpi_ut_detect_hex_prefix(char ** string)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  
acpi_ut_remove_hex_prefix(char ** string)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  
acpi_ut_detect_octal_prefix(char ** string)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
acpi_ut_insert_digit(u64 * accumulated_value,u32 base,int ascii_digit)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(*accumulated_value, base, &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(product,
347  				  acpi_ut_ascii_char_to_hex(ascii_digit),
348  				  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
acpi_ut_strtoul_multiply64(u64 multiplicand,u32 base,u64 * out_product)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, base, &quotient, 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  
acpi_ut_strtoul_add64(u64 addend1,u32 digit,u64 * out_sum)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