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