xref: /aosp_15_r20/external/curl/lib/strtoofft.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker 
25*6236dae4SAndroid Build Coastguard Worker #include <errno.h>
26*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
27*6236dae4SAndroid Build Coastguard Worker 
28*6236dae4SAndroid Build Coastguard Worker #include "strtoofft.h"
29*6236dae4SAndroid Build Coastguard Worker 
30*6236dae4SAndroid Build Coastguard Worker /*
31*6236dae4SAndroid Build Coastguard Worker  * NOTE:
32*6236dae4SAndroid Build Coastguard Worker  *
33*6236dae4SAndroid Build Coastguard Worker  * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we
34*6236dae4SAndroid Build Coastguard Worker  * could use in case strtoll() does not exist... See
35*6236dae4SAndroid Build Coastguard Worker  * https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html
36*6236dae4SAndroid Build Coastguard Worker  */
37*6236dae4SAndroid Build Coastguard Worker 
38*6236dae4SAndroid Build Coastguard Worker #if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
39*6236dae4SAndroid Build Coastguard Worker #  ifdef HAVE_STRTOLL
40*6236dae4SAndroid Build Coastguard Worker #    define strtooff strtoll
41*6236dae4SAndroid Build Coastguard Worker #  else
42*6236dae4SAndroid Build Coastguard Worker #    if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64)
43*6236dae4SAndroid Build Coastguard Worker #      if defined(_SAL_VERSION)
44*6236dae4SAndroid Build Coastguard Worker          _Check_return_ _CRTIMP __int64 __cdecl _strtoi64(
45*6236dae4SAndroid Build Coastguard Worker              _In_z_ const char *_String,
46*6236dae4SAndroid Build Coastguard Worker              _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix);
47*6236dae4SAndroid Build Coastguard Worker #      else
48*6236dae4SAndroid Build Coastguard Worker          _CRTIMP __int64 __cdecl _strtoi64(const char *_String,
49*6236dae4SAndroid Build Coastguard Worker                                            char **_EndPtr, int _Radix);
50*6236dae4SAndroid Build Coastguard Worker #      endif
51*6236dae4SAndroid Build Coastguard Worker #      define strtooff _strtoi64
52*6236dae4SAndroid Build Coastguard Worker #    else
53*6236dae4SAndroid Build Coastguard Worker #      define PRIVATE_STRTOOFF 1
54*6236dae4SAndroid Build Coastguard Worker #    endif
55*6236dae4SAndroid Build Coastguard Worker #  endif
56*6236dae4SAndroid Build Coastguard Worker #else
57*6236dae4SAndroid Build Coastguard Worker #  define strtooff strtol
58*6236dae4SAndroid Build Coastguard Worker #endif
59*6236dae4SAndroid Build Coastguard Worker 
60*6236dae4SAndroid Build Coastguard Worker #ifdef PRIVATE_STRTOOFF
61*6236dae4SAndroid Build Coastguard Worker 
62*6236dae4SAndroid Build Coastguard Worker /* Range tests can be used for alphanum decoding if characters are consecutive,
63*6236dae4SAndroid Build Coastguard Worker    like in ASCII. Else an array is scanned. Determine this condition now. */
64*6236dae4SAndroid Build Coastguard Worker 
65*6236dae4SAndroid Build Coastguard Worker #if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25
66*6236dae4SAndroid Build Coastguard Worker 
67*6236dae4SAndroid Build Coastguard Worker #define NO_RANGE_TEST
68*6236dae4SAndroid Build Coastguard Worker 
69*6236dae4SAndroid Build Coastguard Worker static const char valchars[] =
70*6236dae4SAndroid Build Coastguard Worker             "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
71*6236dae4SAndroid Build Coastguard Worker #endif
72*6236dae4SAndroid Build Coastguard Worker 
73*6236dae4SAndroid Build Coastguard Worker static int get_char(char c, int base);
74*6236dae4SAndroid Build Coastguard Worker 
75*6236dae4SAndroid Build Coastguard Worker /**
76*6236dae4SAndroid Build Coastguard Worker  * Custom version of the strtooff function. This extracts a curl_off_t
77*6236dae4SAndroid Build Coastguard Worker  * value from the given input string and returns it.
78*6236dae4SAndroid Build Coastguard Worker  */
strtooff(const char * nptr,char ** endptr,int base)79*6236dae4SAndroid Build Coastguard Worker static curl_off_t strtooff(const char *nptr, char **endptr, int base)
80*6236dae4SAndroid Build Coastguard Worker {
81*6236dae4SAndroid Build Coastguard Worker   char *end;
82*6236dae4SAndroid Build Coastguard Worker   bool is_negative = FALSE;
83*6236dae4SAndroid Build Coastguard Worker   bool overflow = FALSE;
84*6236dae4SAndroid Build Coastguard Worker   int i;
85*6236dae4SAndroid Build Coastguard Worker   curl_off_t value = 0;
86*6236dae4SAndroid Build Coastguard Worker 
87*6236dae4SAndroid Build Coastguard Worker   /* Skip leading whitespace. */
88*6236dae4SAndroid Build Coastguard Worker   end = (char *)nptr;
89*6236dae4SAndroid Build Coastguard Worker   while(ISBLANK(end[0])) {
90*6236dae4SAndroid Build Coastguard Worker     end++;
91*6236dae4SAndroid Build Coastguard Worker   }
92*6236dae4SAndroid Build Coastguard Worker 
93*6236dae4SAndroid Build Coastguard Worker   /* Handle the sign, if any. */
94*6236dae4SAndroid Build Coastguard Worker   if(end[0] == '-') {
95*6236dae4SAndroid Build Coastguard Worker     is_negative = TRUE;
96*6236dae4SAndroid Build Coastguard Worker     end++;
97*6236dae4SAndroid Build Coastguard Worker   }
98*6236dae4SAndroid Build Coastguard Worker   else if(end[0] == '+') {
99*6236dae4SAndroid Build Coastguard Worker     end++;
100*6236dae4SAndroid Build Coastguard Worker   }
101*6236dae4SAndroid Build Coastguard Worker   else if(end[0] == '\0') {
102*6236dae4SAndroid Build Coastguard Worker     /* We had nothing but perhaps some whitespace -- there was no number. */
103*6236dae4SAndroid Build Coastguard Worker     if(endptr) {
104*6236dae4SAndroid Build Coastguard Worker       *endptr = end;
105*6236dae4SAndroid Build Coastguard Worker     }
106*6236dae4SAndroid Build Coastguard Worker     return 0;
107*6236dae4SAndroid Build Coastguard Worker   }
108*6236dae4SAndroid Build Coastguard Worker 
109*6236dae4SAndroid Build Coastguard Worker   /* Handle special beginnings, if present and allowed. */
110*6236dae4SAndroid Build Coastguard Worker   if(end[0] == '0' && end[1] == 'x') {
111*6236dae4SAndroid Build Coastguard Worker     if(base == 16 || base == 0) {
112*6236dae4SAndroid Build Coastguard Worker       end += 2;
113*6236dae4SAndroid Build Coastguard Worker       base = 16;
114*6236dae4SAndroid Build Coastguard Worker     }
115*6236dae4SAndroid Build Coastguard Worker   }
116*6236dae4SAndroid Build Coastguard Worker   else if(end[0] == '0') {
117*6236dae4SAndroid Build Coastguard Worker     if(base == 8 || base == 0) {
118*6236dae4SAndroid Build Coastguard Worker       end++;
119*6236dae4SAndroid Build Coastguard Worker       base = 8;
120*6236dae4SAndroid Build Coastguard Worker     }
121*6236dae4SAndroid Build Coastguard Worker   }
122*6236dae4SAndroid Build Coastguard Worker 
123*6236dae4SAndroid Build Coastguard Worker   /* Matching strtol, if the base is 0 and it does not look like
124*6236dae4SAndroid Build Coastguard Worker    * the number is octal or hex, we assume it is base 10.
125*6236dae4SAndroid Build Coastguard Worker    */
126*6236dae4SAndroid Build Coastguard Worker   if(base == 0) {
127*6236dae4SAndroid Build Coastguard Worker     base = 10;
128*6236dae4SAndroid Build Coastguard Worker   }
129*6236dae4SAndroid Build Coastguard Worker 
130*6236dae4SAndroid Build Coastguard Worker   /* Loop handling digits. */
131*6236dae4SAndroid Build Coastguard Worker   for(i = get_char(end[0], base);
132*6236dae4SAndroid Build Coastguard Worker       i != -1;
133*6236dae4SAndroid Build Coastguard Worker       end++, i = get_char(end[0], base)) {
134*6236dae4SAndroid Build Coastguard Worker 
135*6236dae4SAndroid Build Coastguard Worker     if(value > (CURL_OFF_T_MAX - i) / base) {
136*6236dae4SAndroid Build Coastguard Worker       overflow = TRUE;
137*6236dae4SAndroid Build Coastguard Worker       break;
138*6236dae4SAndroid Build Coastguard Worker     }
139*6236dae4SAndroid Build Coastguard Worker     value = base * value + i;
140*6236dae4SAndroid Build Coastguard Worker   }
141*6236dae4SAndroid Build Coastguard Worker 
142*6236dae4SAndroid Build Coastguard Worker   if(!overflow) {
143*6236dae4SAndroid Build Coastguard Worker     if(is_negative) {
144*6236dae4SAndroid Build Coastguard Worker       /* Fix the sign. */
145*6236dae4SAndroid Build Coastguard Worker       value *= -1;
146*6236dae4SAndroid Build Coastguard Worker     }
147*6236dae4SAndroid Build Coastguard Worker   }
148*6236dae4SAndroid Build Coastguard Worker   else {
149*6236dae4SAndroid Build Coastguard Worker     if(is_negative)
150*6236dae4SAndroid Build Coastguard Worker       value = CURL_OFF_T_MIN;
151*6236dae4SAndroid Build Coastguard Worker     else
152*6236dae4SAndroid Build Coastguard Worker       value = CURL_OFF_T_MAX;
153*6236dae4SAndroid Build Coastguard Worker 
154*6236dae4SAndroid Build Coastguard Worker     errno = ERANGE;
155*6236dae4SAndroid Build Coastguard Worker   }
156*6236dae4SAndroid Build Coastguard Worker 
157*6236dae4SAndroid Build Coastguard Worker   if(endptr)
158*6236dae4SAndroid Build Coastguard Worker     *endptr = end;
159*6236dae4SAndroid Build Coastguard Worker 
160*6236dae4SAndroid Build Coastguard Worker   return value;
161*6236dae4SAndroid Build Coastguard Worker }
162*6236dae4SAndroid Build Coastguard Worker 
163*6236dae4SAndroid Build Coastguard Worker /**
164*6236dae4SAndroid Build Coastguard Worker  * Returns the value of c in the given base, or -1 if c cannot
165*6236dae4SAndroid Build Coastguard Worker  * be interpreted properly in that base (i.e., is out of range,
166*6236dae4SAndroid Build Coastguard Worker  * is a null, etc.).
167*6236dae4SAndroid Build Coastguard Worker  *
168*6236dae4SAndroid Build Coastguard Worker  * @param c     the character to interpret according to base
169*6236dae4SAndroid Build Coastguard Worker  * @param base  the base in which to interpret c
170*6236dae4SAndroid Build Coastguard Worker  *
171*6236dae4SAndroid Build Coastguard Worker  * @return  the value of c in base, or -1 if c is not in range
172*6236dae4SAndroid Build Coastguard Worker  */
get_char(char c,int base)173*6236dae4SAndroid Build Coastguard Worker static int get_char(char c, int base)
174*6236dae4SAndroid Build Coastguard Worker {
175*6236dae4SAndroid Build Coastguard Worker #ifndef NO_RANGE_TEST
176*6236dae4SAndroid Build Coastguard Worker   int value = -1;
177*6236dae4SAndroid Build Coastguard Worker   if(c <= '9' && c >= '0') {
178*6236dae4SAndroid Build Coastguard Worker     value = c - '0';
179*6236dae4SAndroid Build Coastguard Worker   }
180*6236dae4SAndroid Build Coastguard Worker   else if(c <= 'Z' && c >= 'A') {
181*6236dae4SAndroid Build Coastguard Worker     value = c - 'A' + 10;
182*6236dae4SAndroid Build Coastguard Worker   }
183*6236dae4SAndroid Build Coastguard Worker   else if(c <= 'z' && c >= 'a') {
184*6236dae4SAndroid Build Coastguard Worker     value = c - 'a' + 10;
185*6236dae4SAndroid Build Coastguard Worker   }
186*6236dae4SAndroid Build Coastguard Worker #else
187*6236dae4SAndroid Build Coastguard Worker   const char *cp;
188*6236dae4SAndroid Build Coastguard Worker   int value;
189*6236dae4SAndroid Build Coastguard Worker 
190*6236dae4SAndroid Build Coastguard Worker   cp = memchr(valchars, c, 10 + 26 + 26);
191*6236dae4SAndroid Build Coastguard Worker 
192*6236dae4SAndroid Build Coastguard Worker   if(!cp)
193*6236dae4SAndroid Build Coastguard Worker     return -1;
194*6236dae4SAndroid Build Coastguard Worker 
195*6236dae4SAndroid Build Coastguard Worker   value = cp - valchars;
196*6236dae4SAndroid Build Coastguard Worker 
197*6236dae4SAndroid Build Coastguard Worker   if(value >= 10 + 26)
198*6236dae4SAndroid Build Coastguard Worker     value -= 26;                /* Lowercase. */
199*6236dae4SAndroid Build Coastguard Worker #endif
200*6236dae4SAndroid Build Coastguard Worker 
201*6236dae4SAndroid Build Coastguard Worker   if(value >= base) {
202*6236dae4SAndroid Build Coastguard Worker     value = -1;
203*6236dae4SAndroid Build Coastguard Worker   }
204*6236dae4SAndroid Build Coastguard Worker 
205*6236dae4SAndroid Build Coastguard Worker   return value;
206*6236dae4SAndroid Build Coastguard Worker }
207*6236dae4SAndroid Build Coastguard Worker #endif  /* Only present if we need strtoll, but do not have it. */
208*6236dae4SAndroid Build Coastguard Worker 
209*6236dae4SAndroid Build Coastguard Worker /*
210*6236dae4SAndroid Build Coastguard Worker  * Parse a *positive* up to 64-bit number written in ASCII.
211*6236dae4SAndroid Build Coastguard Worker  */
curlx_strtoofft(const char * str,char ** endp,int base,curl_off_t * num)212*6236dae4SAndroid Build Coastguard Worker CURLofft curlx_strtoofft(const char *str, char **endp, int base,
213*6236dae4SAndroid Build Coastguard Worker                          curl_off_t *num)
214*6236dae4SAndroid Build Coastguard Worker {
215*6236dae4SAndroid Build Coastguard Worker   char *end = NULL;
216*6236dae4SAndroid Build Coastguard Worker   curl_off_t number;
217*6236dae4SAndroid Build Coastguard Worker   errno = 0;
218*6236dae4SAndroid Build Coastguard Worker   *num = 0; /* clear by default */
219*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(base); /* starting now, avoid base zero */
220*6236dae4SAndroid Build Coastguard Worker 
221*6236dae4SAndroid Build Coastguard Worker   while(*str && ISBLANK(*str))
222*6236dae4SAndroid Build Coastguard Worker     str++;
223*6236dae4SAndroid Build Coastguard Worker   if(('-' == *str) || (ISSPACE(*str))) {
224*6236dae4SAndroid Build Coastguard Worker     if(endp)
225*6236dae4SAndroid Build Coastguard Worker       *endp = (char *)str; /* did not actually move */
226*6236dae4SAndroid Build Coastguard Worker     return CURL_OFFT_INVAL; /* nothing parsed */
227*6236dae4SAndroid Build Coastguard Worker   }
228*6236dae4SAndroid Build Coastguard Worker   number = strtooff(str, &end, base);
229*6236dae4SAndroid Build Coastguard Worker   if(endp)
230*6236dae4SAndroid Build Coastguard Worker     *endp = end;
231*6236dae4SAndroid Build Coastguard Worker   if(errno == ERANGE)
232*6236dae4SAndroid Build Coastguard Worker     /* overflow/underflow */
233*6236dae4SAndroid Build Coastguard Worker     return CURL_OFFT_FLOW;
234*6236dae4SAndroid Build Coastguard Worker   else if(str == end)
235*6236dae4SAndroid Build Coastguard Worker     /* nothing parsed */
236*6236dae4SAndroid Build Coastguard Worker     return CURL_OFFT_INVAL;
237*6236dae4SAndroid Build Coastguard Worker 
238*6236dae4SAndroid Build Coastguard Worker   *num = number;
239*6236dae4SAndroid Build Coastguard Worker   return CURL_OFFT_OK;
240*6236dae4SAndroid Build Coastguard Worker }
241