Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 12ACPI_MODULE_NAME("utstrsuppt")
 13
 14/* Local prototypes */
 15static acpi_status
 16acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit);
 17
 18static acpi_status
 19acpi_ut_strtoul_multiply64(u64 multiplicand, u32 base, u64 *out_product);
 20
 21static 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
 40acpi_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
 89acpi_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
138acpi_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
185char 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
210char 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
232u8 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
257u8 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
295static acpi_status
296acpi_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
334static acpi_status
335acpi_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, &quotient, 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
388static 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}