1 /*******************************************************************************
2 *
3 * Module Name: utstrsuppt - Support functions for string-to-integer conversion
4 *
5 ******************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2022, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44 #include "acpi.h"
45 #include "accommon.h"
46
47 #define _COMPONENT ACPI_UTILITIES
48 ACPI_MODULE_NAME ("utstrsuppt")
49
50
51 /* Local prototypes */
52
53 static ACPI_STATUS
54 AcpiUtInsertDigit (
55 UINT64 *AccumulatedValue,
56 UINT32 Base,
57 int AsciiDigit);
58
59 static ACPI_STATUS
60 AcpiUtStrtoulMultiply64 (
61 UINT64 Multiplicand,
62 UINT32 Base,
63 UINT64 *OutProduct);
64
65 static ACPI_STATUS
66 AcpiUtStrtoulAdd64 (
67 UINT64 Addend1,
68 UINT32 Digit,
69 UINT64 *OutSum);
70
71
72 /*******************************************************************************
73 *
74 * FUNCTION: AcpiUtConvertOctalString
75 *
76 * PARAMETERS: String - Null terminated input string
77 * ReturnValuePtr - Where the converted value is returned
78 *
79 * RETURN: Status and 64-bit converted integer
80 *
81 * DESCRIPTION: Performs a base 8 conversion of the input string to an
82 * integer value, either 32 or 64 bits.
83 *
84 * NOTE: Maximum 64-bit unsigned octal value is 01777777777777777777777
85 * Maximum 32-bit unsigned octal value is 037777777777
86 *
87 ******************************************************************************/
88
89 ACPI_STATUS
AcpiUtConvertOctalString(char * String,UINT64 * ReturnValuePtr)90 AcpiUtConvertOctalString (
91 char *String,
92 UINT64 *ReturnValuePtr)
93 {
94 UINT64 AccumulatedValue = 0;
95 ACPI_STATUS Status = AE_OK;
96
97
98 /* Convert each ASCII byte in the input string */
99
100 while (*String)
101 {
102 /*
103 * Character must be ASCII 0-7, otherwise:
104 * 1) Runtime: terminate with no error, per the ACPI spec
105 * 2) Compiler: return an error
106 */
107 if (!(ACPI_IS_OCTAL_DIGIT (*String)))
108 {
109 #ifdef ACPI_ASL_COMPILER
110 Status = AE_BAD_OCTAL_CONSTANT;
111 #endif
112 break;
113 }
114
115 /* Convert and insert this octal digit into the accumulator */
116
117 Status = AcpiUtInsertDigit (&AccumulatedValue, 8, *String);
118 if (ACPI_FAILURE (Status))
119 {
120 Status = AE_OCTAL_OVERFLOW;
121 break;
122 }
123
124 String++;
125 }
126
127 /* Always return the value that has been accumulated */
128
129 *ReturnValuePtr = AccumulatedValue;
130 return (Status);
131 }
132
133
134 /*******************************************************************************
135 *
136 * FUNCTION: AcpiUtConvertDecimalString
137 *
138 * PARAMETERS: String - Null terminated input string
139 * ReturnValuePtr - Where the converted value is returned
140 *
141 * RETURN: Status and 64-bit converted integer
142 *
143 * DESCRIPTION: Performs a base 10 conversion of the input string to an
144 * integer value, either 32 or 64 bits.
145 *
146 * NOTE: Maximum 64-bit unsigned decimal value is 18446744073709551615
147 * Maximum 32-bit unsigned decimal value is 4294967295
148 *
149 ******************************************************************************/
150
151 ACPI_STATUS
AcpiUtConvertDecimalString(char * String,UINT64 * ReturnValuePtr)152 AcpiUtConvertDecimalString (
153 char *String,
154 UINT64 *ReturnValuePtr)
155 {
156 UINT64 AccumulatedValue = 0;
157 ACPI_STATUS Status = AE_OK;
158
159
160 /* Convert each ASCII byte in the input string */
161
162 while (*String)
163 {
164 /*
165 * Character must be ASCII 0-9, otherwise:
166 * 1) Runtime: terminate with no error, per the ACPI spec
167 * 2) Compiler: return an error
168 */
169 if (!isdigit ((int) *String))
170 {
171 #ifdef ACPI_ASL_COMPILER
172 Status = AE_BAD_DECIMAL_CONSTANT;
173 #endif
174 break;
175 }
176
177 /* Convert and insert this decimal digit into the accumulator */
178
179 Status = AcpiUtInsertDigit (&AccumulatedValue, 10, *String);
180 if (ACPI_FAILURE (Status))
181 {
182 Status = AE_DECIMAL_OVERFLOW;
183 break;
184 }
185
186 String++;
187 }
188
189 /* Always return the value that has been accumulated */
190
191 *ReturnValuePtr = AccumulatedValue;
192 return (Status);
193 }
194
195
196 /*******************************************************************************
197 *
198 * FUNCTION: AcpiUtConvertHexString
199 *
200 * PARAMETERS: String - Null terminated input string
201 * ReturnValuePtr - Where the converted value is returned
202 *
203 * RETURN: Status and 64-bit converted integer
204 *
205 * DESCRIPTION: Performs a base 16 conversion of the input string to an
206 * integer value, either 32 or 64 bits.
207 *
208 * NOTE: Maximum 64-bit unsigned hex value is 0xFFFFFFFFFFFFFFFF
209 * Maximum 32-bit unsigned hex value is 0xFFFFFFFF
210 *
211 ******************************************************************************/
212
213 ACPI_STATUS
AcpiUtConvertHexString(char * String,UINT64 * ReturnValuePtr)214 AcpiUtConvertHexString (
215 char *String,
216 UINT64 *ReturnValuePtr)
217 {
218 UINT64 AccumulatedValue = 0;
219 ACPI_STATUS Status = AE_OK;
220
221
222 /* Convert each ASCII byte in the input string */
223
224 while (*String)
225 {
226 /*
227 * Character must be ASCII A-F, a-f, or 0-9, otherwise:
228 * 1) Runtime: terminate with no error, per the ACPI spec
229 * 2) Compiler: return an error
230 */
231 if (!isxdigit ((int) *String))
232 {
233 #ifdef ACPI_ASL_COMPILER
234 Status = AE_BAD_HEX_CONSTANT;
235 #endif
236 break;
237 }
238
239 /* Convert and insert this hex digit into the accumulator */
240
241 Status = AcpiUtInsertDigit (&AccumulatedValue, 16, *String);
242 if (ACPI_FAILURE (Status))
243 {
244 Status = AE_HEX_OVERFLOW;
245 break;
246 }
247
248 String++;
249 }
250
251 /* Always return the value that has been accumulated */
252
253 *ReturnValuePtr = AccumulatedValue;
254 return (Status);
255 }
256
257
258 /*******************************************************************************
259 *
260 * FUNCTION: AcpiUtRemoveLeadingZeros
261 *
262 * PARAMETERS: String - Pointer to input ASCII string
263 *
264 * RETURN: Next character after any leading zeros. This character may be
265 * used by the caller to detect end-of-string.
266 *
267 * DESCRIPTION: Remove any leading zeros in the input string. Return the
268 * next character after the final ASCII zero to enable the caller
269 * to check for the end of the string (NULL terminator).
270 *
271 ******************************************************************************/
272
273 char
AcpiUtRemoveLeadingZeros(char ** String)274 AcpiUtRemoveLeadingZeros (
275 char **String)
276 {
277
278 while (**String == ACPI_ASCII_ZERO)
279 {
280 *String += 1;
281 }
282
283 return (**String);
284 }
285
286
287 /*******************************************************************************
288 *
289 * FUNCTION: AcpiUtRemoveWhitespace
290 *
291 * PARAMETERS: String - Pointer to input ASCII string
292 *
293 * RETURN: Next character after any whitespace. This character may be
294 * used by the caller to detect end-of-string.
295 *
296 * DESCRIPTION: Remove any leading whitespace in the input string. Return the
297 * next character after the final ASCII zero to enable the caller
298 * to check for the end of the string (NULL terminator).
299 *
300 ******************************************************************************/
301
302 char
AcpiUtRemoveWhitespace(char ** String)303 AcpiUtRemoveWhitespace (
304 char **String)
305 {
306
307 while (isspace ((UINT8) **String))
308 {
309 *String += 1;
310 }
311
312 return (**String);
313 }
314
315
316 /*******************************************************************************
317 *
318 * FUNCTION: AcpiUtDetectHexPrefix
319 *
320 * PARAMETERS: String - Pointer to input ASCII string
321 *
322 * RETURN: TRUE if a "0x" prefix was found at the start of the string
323 *
324 * DESCRIPTION: Detect and remove a hex "0x" prefix
325 *
326 ******************************************************************************/
327
328 BOOLEAN
AcpiUtDetectHexPrefix(char ** String)329 AcpiUtDetectHexPrefix (
330 char **String)
331 {
332 char *InitialPosition = *String;
333
334 AcpiUtRemoveHexPrefix (String);
335 if (*String != InitialPosition)
336 {
337 return (TRUE); /* String is past leading 0x */
338 }
339
340 return (FALSE); /* Not a hex string */
341 }
342
343
344 /*******************************************************************************
345 *
346 * FUNCTION: AcpiUtRemoveHexPrefix
347 *
348 * PARAMETERS: String - Pointer to input ASCII string
349 *
350 * RETURN: none
351 *
352 * DESCRIPTION: Remove a hex "0x" prefix
353 *
354 ******************************************************************************/
355
356 void
AcpiUtRemoveHexPrefix(char ** String)357 AcpiUtRemoveHexPrefix (
358 char **String)
359 {
360 if ((**String == ACPI_ASCII_ZERO) &&
361 (tolower ((int) *(*String + 1)) == 'x'))
362 {
363 *String += 2; /* Go past the leading 0x */
364 }
365 }
366
367
368 /*******************************************************************************
369 *
370 * FUNCTION: AcpiUtDetectOctalPrefix
371 *
372 * PARAMETERS: String - Pointer to input ASCII string
373 *
374 * RETURN: True if an octal "0" prefix was found at the start of the
375 * string
376 *
377 * DESCRIPTION: Detect and remove an octal prefix (zero)
378 *
379 ******************************************************************************/
380
381 BOOLEAN
AcpiUtDetectOctalPrefix(char ** String)382 AcpiUtDetectOctalPrefix (
383 char **String)
384 {
385
386 if (**String == ACPI_ASCII_ZERO)
387 {
388 *String += 1; /* Go past the leading 0 */
389 return (TRUE);
390 }
391
392 return (FALSE); /* Not an octal string */
393 }
394
395
396 /*******************************************************************************
397 *
398 * FUNCTION: AcpiUtInsertDigit
399 *
400 * PARAMETERS: AccumulatedValue - Current value of the integer value
401 * accumulator. The new value is
402 * returned here.
403 * Base - Radix, either 8/10/16
404 * AsciiDigit - ASCII single digit to be inserted
405 *
406 * RETURN: Status and result of the convert/insert operation. The only
407 * possible returned exception code is numeric overflow of
408 * either the multiply or add conversion operations.
409 *
410 * DESCRIPTION: Generic conversion and insertion function for all bases:
411 *
412 * 1) Multiply the current accumulated/converted value by the
413 * base in order to make room for the new character.
414 *
415 * 2) Convert the new character to binary and add it to the
416 * current accumulated value.
417 *
418 * Note: The only possible exception indicates an integer
419 * overflow (AE_NUMERIC_OVERFLOW)
420 *
421 ******************************************************************************/
422
423 static ACPI_STATUS
AcpiUtInsertDigit(UINT64 * AccumulatedValue,UINT32 Base,int AsciiDigit)424 AcpiUtInsertDigit (
425 UINT64 *AccumulatedValue,
426 UINT32 Base,
427 int AsciiDigit)
428 {
429 ACPI_STATUS Status;
430 UINT64 Product;
431
432
433 /* Make room in the accumulated value for the incoming digit */
434
435 Status = AcpiUtStrtoulMultiply64 (*AccumulatedValue, Base, &Product);
436 if (ACPI_FAILURE (Status))
437 {
438 return (Status);
439 }
440
441 /* Add in the new digit, and store the sum to the accumulated value */
442
443 Status = AcpiUtStrtoulAdd64 (Product, AcpiUtAsciiCharToHex (AsciiDigit),
444 AccumulatedValue);
445
446 return (Status);
447 }
448
449
450 /*******************************************************************************
451 *
452 * FUNCTION: AcpiUtStrtoulMultiply64
453 *
454 * PARAMETERS: Multiplicand - Current accumulated converted integer
455 * Base - Base/Radix
456 * OutProduct - Where the product is returned
457 *
458 * RETURN: Status and 64-bit product
459 *
460 * DESCRIPTION: Multiply two 64-bit values, with checking for 64-bit overflow as
461 * well as 32-bit overflow if necessary (if the current global
462 * integer width is 32).
463 *
464 ******************************************************************************/
465
466 static ACPI_STATUS
AcpiUtStrtoulMultiply64(UINT64 Multiplicand,UINT32 Base,UINT64 * OutProduct)467 AcpiUtStrtoulMultiply64 (
468 UINT64 Multiplicand,
469 UINT32 Base,
470 UINT64 *OutProduct)
471 {
472 UINT64 Product;
473 UINT64 Quotient;
474
475
476 /* Exit if either operand is zero */
477
478 *OutProduct = 0;
479 if (!Multiplicand || !Base)
480 {
481 return (AE_OK);
482 }
483
484 /*
485 * Check for 64-bit overflow before the actual multiplication.
486 *
487 * Notes: 64-bit division is often not supported on 32-bit platforms
488 * (it requires a library function), Therefore ACPICA has a local
489 * 64-bit divide function. Also, Multiplier is currently only used
490 * as the radix (8/10/16), to the 64/32 divide will always work.
491 */
492 AcpiUtShortDivide (ACPI_UINT64_MAX, Base, &Quotient, NULL);
493 if (Multiplicand > Quotient)
494 {
495 return (AE_NUMERIC_OVERFLOW);
496 }
497
498 Product = Multiplicand * Base;
499
500 /* Check for 32-bit overflow if necessary */
501
502 if ((AcpiGbl_IntegerBitWidth == 32) && (Product > ACPI_UINT32_MAX))
503 {
504 return (AE_NUMERIC_OVERFLOW);
505 }
506
507 *OutProduct = Product;
508 return (AE_OK);
509 }
510
511
512 /*******************************************************************************
513 *
514 * FUNCTION: AcpiUtStrtoulAdd64
515 *
516 * PARAMETERS: Addend1 - Current accumulated converted integer
517 * Digit - New hex value/char
518 * OutSum - Where sum is returned (Accumulator)
519 *
520 * RETURN: Status and 64-bit sum
521 *
522 * DESCRIPTION: Add two 64-bit values, with checking for 64-bit overflow as
523 * well as 32-bit overflow if necessary (if the current global
524 * integer width is 32).
525 *
526 ******************************************************************************/
527
528 static ACPI_STATUS
AcpiUtStrtoulAdd64(UINT64 Addend1,UINT32 Digit,UINT64 * OutSum)529 AcpiUtStrtoulAdd64 (
530 UINT64 Addend1,
531 UINT32 Digit,
532 UINT64 *OutSum)
533 {
534 UINT64 Sum;
535
536
537 /* Check for 64-bit overflow before the actual addition */
538
539 if ((Addend1 > 0) && (Digit > (ACPI_UINT64_MAX - Addend1)))
540 {
541 return (AE_NUMERIC_OVERFLOW);
542 }
543
544 Sum = Addend1 + Digit;
545
546 /* Check for 32-bit overflow if necessary */
547
548 if ((AcpiGbl_IntegerBitWidth == 32) && (Sum > ACPI_UINT32_MAX))
549 {
550 return (AE_NUMERIC_OVERFLOW);
551 }
552
553 *OutSum = Sum;
554 return (AE_OK);
555 }
556