113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include <errno.h> 2613498266Sopenharmony_ci#include "curl_setup.h" 2713498266Sopenharmony_ci 2813498266Sopenharmony_ci#include "strtoofft.h" 2913498266Sopenharmony_ci 3013498266Sopenharmony_ci/* 3113498266Sopenharmony_ci * NOTE: 3213498266Sopenharmony_ci * 3313498266Sopenharmony_ci * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we 3413498266Sopenharmony_ci * could use in case strtoll() doesn't exist... See 3513498266Sopenharmony_ci * https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html 3613498266Sopenharmony_ci */ 3713498266Sopenharmony_ci 3813498266Sopenharmony_ci#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) 3913498266Sopenharmony_ci# ifdef HAVE_STRTOLL 4013498266Sopenharmony_ci# define strtooff strtoll 4113498266Sopenharmony_ci# else 4213498266Sopenharmony_ci# if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64) 4313498266Sopenharmony_ci# if defined(_SAL_VERSION) 4413498266Sopenharmony_ci _Check_return_ _CRTIMP __int64 __cdecl _strtoi64( 4513498266Sopenharmony_ci _In_z_ const char *_String, 4613498266Sopenharmony_ci _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix); 4713498266Sopenharmony_ci# else 4813498266Sopenharmony_ci _CRTIMP __int64 __cdecl _strtoi64(const char *_String, 4913498266Sopenharmony_ci char **_EndPtr, int _Radix); 5013498266Sopenharmony_ci# endif 5113498266Sopenharmony_ci# define strtooff _strtoi64 5213498266Sopenharmony_ci# else 5313498266Sopenharmony_ci# define PRIVATE_STRTOOFF 1 5413498266Sopenharmony_ci# endif 5513498266Sopenharmony_ci# endif 5613498266Sopenharmony_ci#else 5713498266Sopenharmony_ci# define strtooff strtol 5813498266Sopenharmony_ci#endif 5913498266Sopenharmony_ci 6013498266Sopenharmony_ci#ifdef PRIVATE_STRTOOFF 6113498266Sopenharmony_ci 6213498266Sopenharmony_ci/* Range tests can be used for alphanum decoding if characters are consecutive, 6313498266Sopenharmony_ci like in ASCII. Else an array is scanned. Determine this condition now. */ 6413498266Sopenharmony_ci 6513498266Sopenharmony_ci#if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25 6613498266Sopenharmony_ci 6713498266Sopenharmony_ci#define NO_RANGE_TEST 6813498266Sopenharmony_ci 6913498266Sopenharmony_cistatic const char valchars[] = 7013498266Sopenharmony_ci "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 7113498266Sopenharmony_ci#endif 7213498266Sopenharmony_ci 7313498266Sopenharmony_cistatic int get_char(char c, int base); 7413498266Sopenharmony_ci 7513498266Sopenharmony_ci/** 7613498266Sopenharmony_ci * Custom version of the strtooff function. This extracts a curl_off_t 7713498266Sopenharmony_ci * value from the given input string and returns it. 7813498266Sopenharmony_ci */ 7913498266Sopenharmony_cistatic curl_off_t strtooff(const char *nptr, char **endptr, int base) 8013498266Sopenharmony_ci{ 8113498266Sopenharmony_ci char *end; 8213498266Sopenharmony_ci int is_negative = 0; 8313498266Sopenharmony_ci int overflow; 8413498266Sopenharmony_ci int i; 8513498266Sopenharmony_ci curl_off_t value = 0; 8613498266Sopenharmony_ci curl_off_t newval; 8713498266Sopenharmony_ci 8813498266Sopenharmony_ci /* Skip leading whitespace. */ 8913498266Sopenharmony_ci end = (char *)nptr; 9013498266Sopenharmony_ci while(ISBLANK(end[0])) { 9113498266Sopenharmony_ci end++; 9213498266Sopenharmony_ci } 9313498266Sopenharmony_ci 9413498266Sopenharmony_ci /* Handle the sign, if any. */ 9513498266Sopenharmony_ci if(end[0] == '-') { 9613498266Sopenharmony_ci is_negative = 1; 9713498266Sopenharmony_ci end++; 9813498266Sopenharmony_ci } 9913498266Sopenharmony_ci else if(end[0] == '+') { 10013498266Sopenharmony_ci end++; 10113498266Sopenharmony_ci } 10213498266Sopenharmony_ci else if(end[0] == '\0') { 10313498266Sopenharmony_ci /* We had nothing but perhaps some whitespace -- there was no number. */ 10413498266Sopenharmony_ci if(endptr) { 10513498266Sopenharmony_ci *endptr = end; 10613498266Sopenharmony_ci } 10713498266Sopenharmony_ci return 0; 10813498266Sopenharmony_ci } 10913498266Sopenharmony_ci 11013498266Sopenharmony_ci /* Handle special beginnings, if present and allowed. */ 11113498266Sopenharmony_ci if(end[0] == '0' && end[1] == 'x') { 11213498266Sopenharmony_ci if(base == 16 || base == 0) { 11313498266Sopenharmony_ci end += 2; 11413498266Sopenharmony_ci base = 16; 11513498266Sopenharmony_ci } 11613498266Sopenharmony_ci } 11713498266Sopenharmony_ci else if(end[0] == '0') { 11813498266Sopenharmony_ci if(base == 8 || base == 0) { 11913498266Sopenharmony_ci end++; 12013498266Sopenharmony_ci base = 8; 12113498266Sopenharmony_ci } 12213498266Sopenharmony_ci } 12313498266Sopenharmony_ci 12413498266Sopenharmony_ci /* Matching strtol, if the base is 0 and it doesn't look like 12513498266Sopenharmony_ci * the number is octal or hex, we assume it's base 10. 12613498266Sopenharmony_ci */ 12713498266Sopenharmony_ci if(base == 0) { 12813498266Sopenharmony_ci base = 10; 12913498266Sopenharmony_ci } 13013498266Sopenharmony_ci 13113498266Sopenharmony_ci /* Loop handling digits. */ 13213498266Sopenharmony_ci value = 0; 13313498266Sopenharmony_ci overflow = 0; 13413498266Sopenharmony_ci for(i = get_char(end[0], base); 13513498266Sopenharmony_ci i != -1; 13613498266Sopenharmony_ci end++, i = get_char(end[0], base)) { 13713498266Sopenharmony_ci newval = base * value + i; 13813498266Sopenharmony_ci if(newval < value) { 13913498266Sopenharmony_ci /* We've overflowed. */ 14013498266Sopenharmony_ci overflow = 1; 14113498266Sopenharmony_ci break; 14213498266Sopenharmony_ci } 14313498266Sopenharmony_ci else 14413498266Sopenharmony_ci value = newval; 14513498266Sopenharmony_ci } 14613498266Sopenharmony_ci 14713498266Sopenharmony_ci if(!overflow) { 14813498266Sopenharmony_ci if(is_negative) { 14913498266Sopenharmony_ci /* Fix the sign. */ 15013498266Sopenharmony_ci value *= -1; 15113498266Sopenharmony_ci } 15213498266Sopenharmony_ci } 15313498266Sopenharmony_ci else { 15413498266Sopenharmony_ci if(is_negative) 15513498266Sopenharmony_ci value = CURL_OFF_T_MIN; 15613498266Sopenharmony_ci else 15713498266Sopenharmony_ci value = CURL_OFF_T_MAX; 15813498266Sopenharmony_ci 15913498266Sopenharmony_ci errno = ERANGE; 16013498266Sopenharmony_ci } 16113498266Sopenharmony_ci 16213498266Sopenharmony_ci if(endptr) 16313498266Sopenharmony_ci *endptr = end; 16413498266Sopenharmony_ci 16513498266Sopenharmony_ci return value; 16613498266Sopenharmony_ci} 16713498266Sopenharmony_ci 16813498266Sopenharmony_ci/** 16913498266Sopenharmony_ci * Returns the value of c in the given base, or -1 if c cannot 17013498266Sopenharmony_ci * be interpreted properly in that base (i.e., is out of range, 17113498266Sopenharmony_ci * is a null, etc.). 17213498266Sopenharmony_ci * 17313498266Sopenharmony_ci * @param c the character to interpret according to base 17413498266Sopenharmony_ci * @param base the base in which to interpret c 17513498266Sopenharmony_ci * 17613498266Sopenharmony_ci * @return the value of c in base, or -1 if c isn't in range 17713498266Sopenharmony_ci */ 17813498266Sopenharmony_cistatic int get_char(char c, int base) 17913498266Sopenharmony_ci{ 18013498266Sopenharmony_ci#ifndef NO_RANGE_TEST 18113498266Sopenharmony_ci int value = -1; 18213498266Sopenharmony_ci if(c <= '9' && c >= '0') { 18313498266Sopenharmony_ci value = c - '0'; 18413498266Sopenharmony_ci } 18513498266Sopenharmony_ci else if(c <= 'Z' && c >= 'A') { 18613498266Sopenharmony_ci value = c - 'A' + 10; 18713498266Sopenharmony_ci } 18813498266Sopenharmony_ci else if(c <= 'z' && c >= 'a') { 18913498266Sopenharmony_ci value = c - 'a' + 10; 19013498266Sopenharmony_ci } 19113498266Sopenharmony_ci#else 19213498266Sopenharmony_ci const char *cp; 19313498266Sopenharmony_ci int value; 19413498266Sopenharmony_ci 19513498266Sopenharmony_ci cp = memchr(valchars, c, 10 + 26 + 26); 19613498266Sopenharmony_ci 19713498266Sopenharmony_ci if(!cp) 19813498266Sopenharmony_ci return -1; 19913498266Sopenharmony_ci 20013498266Sopenharmony_ci value = cp - valchars; 20113498266Sopenharmony_ci 20213498266Sopenharmony_ci if(value >= 10 + 26) 20313498266Sopenharmony_ci value -= 26; /* Lowercase. */ 20413498266Sopenharmony_ci#endif 20513498266Sopenharmony_ci 20613498266Sopenharmony_ci if(value >= base) { 20713498266Sopenharmony_ci value = -1; 20813498266Sopenharmony_ci } 20913498266Sopenharmony_ci 21013498266Sopenharmony_ci return value; 21113498266Sopenharmony_ci} 21213498266Sopenharmony_ci#endif /* Only present if we need strtoll, but don't have it. */ 21313498266Sopenharmony_ci 21413498266Sopenharmony_ci/* 21513498266Sopenharmony_ci * Parse a *positive* up to 64 bit number written in ascii. 21613498266Sopenharmony_ci */ 21713498266Sopenharmony_ciCURLofft curlx_strtoofft(const char *str, char **endp, int base, 21813498266Sopenharmony_ci curl_off_t *num) 21913498266Sopenharmony_ci{ 22013498266Sopenharmony_ci char *end; 22113498266Sopenharmony_ci curl_off_t number; 22213498266Sopenharmony_ci errno = 0; 22313498266Sopenharmony_ci *num = 0; /* clear by default */ 22413498266Sopenharmony_ci DEBUGASSERT(base); /* starting now, avoid base zero */ 22513498266Sopenharmony_ci 22613498266Sopenharmony_ci while(*str && ISBLANK(*str)) 22713498266Sopenharmony_ci str++; 22813498266Sopenharmony_ci if(('-' == *str) || (ISSPACE(*str))) { 22913498266Sopenharmony_ci if(endp) 23013498266Sopenharmony_ci *endp = (char *)str; /* didn't actually move */ 23113498266Sopenharmony_ci return CURL_OFFT_INVAL; /* nothing parsed */ 23213498266Sopenharmony_ci } 23313498266Sopenharmony_ci number = strtooff(str, &end, base); 23413498266Sopenharmony_ci if(endp) 23513498266Sopenharmony_ci *endp = end; 23613498266Sopenharmony_ci if(errno == ERANGE) 23713498266Sopenharmony_ci /* overflow/underflow */ 23813498266Sopenharmony_ci return CURL_OFFT_FLOW; 23913498266Sopenharmony_ci else if(str == end) 24013498266Sopenharmony_ci /* nothing parsed */ 24113498266Sopenharmony_ci return CURL_OFFT_INVAL; 24213498266Sopenharmony_ci 24313498266Sopenharmony_ci *num = number; 24413498266Sopenharmony_ci return CURL_OFFT_OK; 24513498266Sopenharmony_ci} 246