1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
24 #include "curl_setup.h"
26 #include "strtoofft.h"
31 * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we
32 * could use in case strtoll() doesn't exist... See
33 * https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html
36 #if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
38 # define strtooff strtoll
40 # if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64)
41 # if defined(_SAL_VERSION)
42 _Check_return_ _CRTIMP __int64 __cdecl _strtoi64(
43 _In_z_ const char *_String,
44 _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix);
46 _CRTIMP __int64 __cdecl _strtoi64(const char *_String,
47 char **_EndPtr, int _Radix);
49 # define strtooff _strtoi64
51 # define PRIVATE_STRTOOFF 1
55 # define strtooff strtol
58 #ifdef PRIVATE_STRTOOFF
60 /* Range tests can be used for alphanum decoding if characters are consecutive,
61 like in ASCII. Else an array is scanned. Determine this condition now. */
63 #if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25
67 static const char valchars[] =
68 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
71 static int get_char(char c, int base);
74 * Custom version of the strtooff function. This extracts a curl_off_t
75 * value from the given input string and returns it.
77 static curl_off_t strtooff(const char *nptr, char **endptr, int base)
86 /* Skip leading whitespace. */
88 while(ISSPACE(end[0])) {
92 /* Handle the sign, if any. */
97 else if(end[0] == '+') {
100 else if(end[0] == '\0') {
101 /* We had nothing but perhaps some whitespace -- there was no number. */
108 /* Handle special beginnings, if present and allowed. */
109 if(end[0] == '0' && end[1] == 'x') {
110 if(base == 16 || base == 0) {
115 else if(end[0] == '0') {
116 if(base == 8 || base == 0) {
122 /* Matching strtol, if the base is 0 and it doesn't look like
123 * the number is octal or hex, we assume it's base 10.
129 /* Loop handling digits. */
132 for(i = get_char(end[0], base);
134 end++, i = get_char(end[0], base)) {
135 newval = base * value + i;
137 /* We've overflowed. */
153 value = CURL_OFF_T_MIN;
155 value = CURL_OFF_T_MAX;
167 * Returns the value of c in the given base, or -1 if c cannot
168 * be interpreted properly in that base (i.e., is out of range,
171 * @param c the character to interpret according to base
172 * @param base the base in which to interpret c
174 * @return the value of c in base, or -1 if c isn't in range
176 static int get_char(char c, int base)
178 #ifndef NO_RANGE_TEST
180 if(c <= '9' && c >= '0') {
183 else if(c <= 'Z' && c >= 'A') {
184 value = c - 'A' + 10;
186 else if(c <= 'z' && c >= 'a') {
187 value = c - 'a' + 10;
193 cp = memchr(valchars, c, 10 + 26 + 26);
198 value = cp - valchars;
201 value -= 26; /* Lowercase. */
210 #endif /* Only present if we need strtoll, but don't have it. */
213 * Parse a *positive* up to 64 bit number written in ascii.
215 CURLofft curlx_strtoofft(const char *str, char **endp, int base,
221 *num = 0; /* clear by default */
225 while(*str && ISSPACE(*str))
229 *endp = (char *)str; /* didn't actually move */
230 return CURL_OFFT_INVAL; /* nothing parsed */
232 number = strtooff(str, &end, base);
236 /* overflow/underflow */
237 return CURL_OFFT_FLOW;
240 return CURL_OFFT_INVAL;