diff --git a/src/rpc/parse.cc b/src/rpc/parse.cc index f39f1cf0..f1e0b3bb 100644 --- a/src/rpc/parse.cc +++ b/src/rpc/parse.cc @@ -115,37 +115,42 @@ parse_value_nothrow(const char* src, int64_t* value, int base, int unit) { if (unit <= 0) throw torrent::input_error("Command::string_to_value_unit(...) received unit <= 0."); - const char* first = src; + if (base != 0 && base != 8 && base != 10 && base != 16) + throw torrent::input_error("Command::string_to_value_unit(...) received invalid base."); - while (std::isspace(static_cast(*first))) - first++; + while (parse_is_space(*src)) + src++; - if ((base == 0 || base == 16) && first[0] == '0' && (first[1] == 'x' || first[1] == 'X')) { - first += 2; - base = 16; - - } else if (base == 0) { - base = 10; - } - - const auto result = std::from_chars(first, first + std::strlen(first), *value, base); - - if (result.ec == std::errc::result_out_of_range) + if (src[0] == '+') return src; - if (result.ec != std::errc()) { + if (src[0] == '-') { + if (base == 8 || base == 16) + return src; + + if (src[1] == '0') + return src; + } + + char* last{}; + + errno = 0; + *value = strtoll(src, &last, base); + + if (errno == ERANGE) + return src; + + if (last == src) { *value = 0; - if (strcasecmp(src, "no") == 0) { *value = 0; return src + strlen("no"); } - if (strcasecmp(src, "yes") == 0) { *value = 1; return src + strlen("yes"); } - if (strcasecmp(src, "true") == 0) { *value = 1; return src + strlen("true"); } + if (strcasecmp(src, "no") == 0) { *value = 0; return src + strlen("no"); } + if (strcasecmp(src, "yes") == 0) { *value = 1; return src + strlen("yes"); } + if (strcasecmp(src, "true") == 0) { *value = 1; return src + strlen("true"); } if (strcasecmp(src, "false") == 0) { *value = 0; return src + strlen("false"); } return src; } - const char* last = result.ptr; - switch (*last) { case 'b': case 'B': ++last; break; diff --git a/src/rpc/parse.h b/src/rpc/parse.h index a7b8f422..7e79f169 100644 --- a/src/rpc/parse.h +++ b/src/rpc/parse.h @@ -1,37 +1,3 @@ -// rTorrent - BitTorrent client -// Copyright (C) 2005-2011, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell - - #ifndef RTORRENT_RPC_PARSE_H #define RTORRENT_RPC_PARSE_H diff --git a/test/rpc/test_parse.cc b/test/rpc/test_parse.cc index ab4b20a3..75251520 100644 --- a/test/rpc/test_parse.cc +++ b/test/rpc/test_parse.cc @@ -42,7 +42,11 @@ TestParse::test_whole_value_bases() { CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("-0x1f", &value)); CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("0022", &value)); - CPPUNIT_ASSERT_EQUAL(int64_t{22}, value); + CPPUNIT_ASSERT_EQUAL(int64_t{022}, value); + + CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("0028", &value)); + CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("+022", &value)); + CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("-022", &value)); CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("22", &value)); CPPUNIT_ASSERT_EQUAL(int64_t{22}, value); @@ -53,13 +57,19 @@ TestParse::test_whole_value_bases() { CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("0x1f", &value, 16)); CPPUNIT_ASSERT_EQUAL(int64_t{31}, value); + CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("22", &value, 8)); + CPPUNIT_ASSERT_EQUAL(int64_t{022}, value); + + CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("022", &value, 8)); + CPPUNIT_ASSERT_EQUAL(int64_t{022}, value); + const char* no_digits = "0x"; CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow(no_digits, &value)); - CPPUNIT_ASSERT_EQUAL(no_digits, rpc::parse_value_nothrow(no_digits, &value)); + CPPUNIT_ASSERT_EQUAL(no_digits + 1, rpc::parse_value_nothrow(no_digits, &value)); const char* bad_digits = "0xzz"; CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow(bad_digits, &value)); - CPPUNIT_ASSERT_EQUAL(bad_digits, rpc::parse_value_nothrow(bad_digits, &value)); + CPPUNIT_ASSERT_EQUAL(bad_digits + 1, rpc::parse_value_nothrow(bad_digits, &value)); } void