refactor: make tr_variantFromBuf() public (#2187)

* refactor: add tr_variantFromBuf() and support inplace json/benc parsing
This commit is contained in:
Charles Kerr 2021-11-17 23:37:35 -06:00 committed by GitHub
parent 36f5d56cfe
commit a79a868257
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 297 additions and 305 deletions

View File

@ -1298,7 +1298,7 @@ bool Application::Impl::call_rpc_for_selected_torrents(std::string const& method
auto* session = core_->get_session();
tr_variantInitDict(&top, 2);
tr_variantDictAddStr(&top, TR_KEY_method, method);
tr_variantDictAddStrView(&top, TR_KEY_method, method);
args = tr_variantDictAddDict(&top, TR_KEY_arguments, 1);
ids = tr_variantDictAddList(args, TR_KEY_ids, 0);
sel_->selected_foreach(
@ -1337,7 +1337,7 @@ void Application::Impl::start_all_torrents()
tr_variant request;
tr_variantInitDict(&request, 1);
tr_variantDictAddStr(&request, TR_KEY_method, "torrent-start"sv);
tr_variantDictAddStrView(&request, TR_KEY_method, "torrent-start"sv);
tr_rpc_request_exec_json(session, &request, nullptr, nullptr);
tr_variantFree(&request);
}
@ -1348,7 +1348,7 @@ void Application::Impl::pause_all_torrents()
tr_variant request;
tr_variantInitDict(&request, 1);
tr_variantDictAddStr(&request, TR_KEY_method, "torrent-stop"sv);
tr_variantDictAddStrView(&request, TR_KEY_method, "torrent-stop"sv);
tr_rpc_request_exec_json(session, &request, nullptr, nullptr);
tr_variantFree(&request);
}

View File

@ -393,7 +393,7 @@ void DetailsDialog::Impl::torrent_set_bool(tr_quark key, bool value)
tr_variant top;
tr_variantInitDict(&top, 2);
tr_variantDictAddStr(&top, TR_KEY_method, "torrent-set"sv);
tr_variantDictAddStrView(&top, TR_KEY_method, "torrent-set"sv);
tr_variant* const args = tr_variantDictAddDict(&top, TR_KEY_arguments, 2);
tr_variantDictAddBool(args, key, value);
tr_variant* const ids = tr_variantDictAddList(args, TR_KEY_ids, ids_.size());
@ -412,7 +412,7 @@ void DetailsDialog::Impl::torrent_set_int(tr_quark key, int value)
tr_variant top;
tr_variantInitDict(&top, 2);
tr_variantDictAddStr(&top, TR_KEY_method, "torrent-set"sv);
tr_variantDictAddStrView(&top, TR_KEY_method, "torrent-set"sv);
tr_variant* const args = tr_variantDictAddDict(&top, TR_KEY_arguments, 2);
tr_variantDictAddInt(args, key, value);
tr_variant* const ids = tr_variantDictAddList(args, TR_KEY_ids, ids_.size());
@ -431,7 +431,7 @@ void DetailsDialog::Impl::torrent_set_real(tr_quark key, double value)
tr_variant top;
tr_variantInitDict(&top, 2);
tr_variantDictAddStr(&top, TR_KEY_method, "torrent-set"sv);
tr_variantDictAddStrView(&top, TR_KEY_method, "torrent-set"sv);
tr_variant* const args = tr_variantDictAddDict(&top, TR_KEY_arguments, 2);
tr_variantDictAddReal(args, key, value);
tr_variant* const ids = tr_variantDictAddList(args, TR_KEY_ids, ids_.size());
@ -2385,7 +2385,7 @@ void DetailsDialog::Impl::on_add_tracker_response(int response, Gtk::Dialog* dia
tr_variant* trackers;
tr_variantInitDict(&top, 2);
tr_variantDictAddStr(&top, TR_KEY_method, "torrent-set"sv);
tr_variantDictAddStrView(&top, TR_KEY_method, "torrent-set"sv);
args = tr_variantDictAddDict(&top, TR_KEY_arguments, 2);
tr_variantDictAddInt(args, TR_KEY_id, torrent_id);
trackers = tr_variantDictAddList(args, TR_KEY_trackerAdd, 1);
@ -2455,7 +2455,7 @@ void DetailsDialog::Impl::on_tracker_list_remove_button_clicked()
tr_variant* trackers;
tr_variantInitDict(&top, 2);
tr_variantDictAddStr(&top, TR_KEY_method, "torrent-set"sv);
tr_variantDictAddStrView(&top, TR_KEY_method, "torrent-set"sv);
args = tr_variantDictAddDict(&top, TR_KEY_arguments, 2);
tr_variantDictAddInt(args, TR_KEY_id, torrent_id);
trackers = tr_variantDictAddList(args, TR_KEY_trackerRemove, 1);

View File

@ -1445,7 +1445,7 @@ void Session::start_now(int id)
{
tr_variant top;
tr_variantInitDict(&top, 2);
tr_variantDictAddStr(&top, TR_KEY_method, "torrent-start-now");
tr_variantDictAddStrView(&top, TR_KEY_method, "torrent-start-now");
auto args = tr_variantDictAddDict(&top, TR_KEY_arguments, 1);
auto ids = tr_variantDictAddList(args, TR_KEY_ids, 1);
@ -1712,7 +1712,7 @@ void Session::port_test()
tr_variant request;
tr_variantInitDict(&request, 2);
tr_variantDictAddStr(&request, TR_KEY_method, "port-test");
tr_variantDictAddStrView(&request, TR_KEY_method, "port-test");
tr_variantDictAddInt(&request, TR_KEY_tag, tag);
impl_->send_rpc_request(
&request,
@ -1743,7 +1743,7 @@ void Session::blocklist_update()
tr_variant request;
tr_variantInitDict(&request, 2);
tr_variantDictAddStr(&request, TR_KEY_method, "blocklist-update");
tr_variantDictAddStrView(&request, TR_KEY_method, "blocklist-update");
tr_variantDictAddInt(&request, TR_KEY_tag, tag);
impl_->send_rpc_request(
&request,

View File

@ -218,7 +218,7 @@ static void on_announce_done(
else
{
tr_variant benc;
bool const variant_loaded = tr_variantFromBenc(&benc, msg) == 0;
auto const variant_loaded = tr_variantFromBuf(&benc, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, msg);
if (tr_env_key_exists("TR_CURL_VERBOSE"))
{
@ -390,7 +390,8 @@ static void on_scrape_done(
else
{
auto top = tr_variant{};
auto const variant_loaded = tr_variantFromBenc(&top, msg) == 0;
auto const variant_loaded = tr_variantFromBuf(&top, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, msg);
if (tr_env_key_exists("TR_CURL_VERBOSE"))
{

View File

@ -477,9 +477,9 @@ static void tr_realMakeMetaInfo(tr_metainfo_builder* builder)
tr_variantDictAddStr(&top, TR_KEY_comment, builder->comment);
}
tr_variantDictAddStr(&top, TR_KEY_created_by, TR_NAME "/" LONG_VERSION_STRING);
tr_variantDictAddStrView(&top, TR_KEY_created_by, TR_NAME "/" LONG_VERSION_STRING);
tr_variantDictAddInt(&top, TR_KEY_creation_date, time(nullptr));
tr_variantDictAddStr(&top, TR_KEY_encoding, "UTF-8");
tr_variantDictAddStrView(&top, TR_KEY_encoding, "UTF-8");
makeInfoDict(tr_variantDictAddDict(&top, TR_KEY_info, 666), builder);
}

View File

@ -1124,7 +1124,7 @@ static void parseLtepHandshake(tr_peerMsgsImpl* msgs, uint32_t len, struct evbuf
msgs->peerSentLtepHandshake = true;
auto val = tr_variant{};
if (tr_variantFromBenc(&val, { tmp, len }) != 0 || !tr_variantIsDict(&val))
if (!tr_variantFromBuf(&val, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, { tmp, len }) || !tr_variantIsDict(&val))
{
dbgmsg(msgs, "GET extended-handshake, couldn't get dictionary");
tr_free(tmp);
@ -1241,7 +1241,7 @@ static void parseUtMetadata(tr_peerMsgsImpl* msgs, uint32_t msglen, struct evbuf
auto dict = tr_variant{};
char const* benc_end = nullptr;
if (tr_variantFromBenc(&dict, std::string_view{ tmp, msglen }, &benc_end) == 0)
if (tr_variantFromBuf(&dict, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, { tmp, msglen }, &benc_end))
{
(void)tr_variantDictFindInt(&dict, TR_KEY_msg_type, &msg_type);
(void)tr_variantDictFindInt(&dict, TR_KEY_piece, &piece);
@ -1310,52 +1310,50 @@ static void parseUtPex(tr_peerMsgsImpl* msgs, uint32_t msglen, struct evbuffer*
tr_peerIoReadBytes(msgs->io, inbuf, tmp, msglen);
tr_variant val;
bool const loaded = tr_variantFromBenc(&val, std::string_view{ tmp, msglen }) == 0;
bool const loaded = tr_variantFromBuf(&val, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, { tmp, msglen });
if (loaded)
{
uint8_t const* added = nullptr;
auto added_len = size_t{};
if (tr_variantDictFindRaw(&val, TR_KEY_added, &added, &added_len))
{
uint8_t const* added_f = nullptr;
auto added_f_len = size_t{};
if (!tr_variantDictFindRaw(&val, TR_KEY_added_f, &added_f, &added_f_len))
{
added_f_len = 0;
added_f = nullptr;
}
auto n = size_t{};
tr_pex* const pex = tr_peerMgrCompactToPex(added, added_len, added_f, added_f_len, &n);
n = std::min(n, size_t{ MAX_PEX_PEER_COUNT });
tr_peerMgrAddPex(tor, TR_PEER_FROM_PEX, pex, n);
tr_free(pex);
}
if (tr_variantDictFindRaw(&val, TR_KEY_added6, &added, &added_len))
{
uint8_t const* added_f = nullptr;
auto added_f_len = size_t{};
if (!tr_variantDictFindRaw(&val, TR_KEY_added6_f, &added_f, &added_f_len))
{
added_f_len = 0;
added_f = nullptr;
}
auto n = size_t{};
tr_pex* const pex = tr_peerMgrCompact6ToPex(added, added_len, added_f, added_f_len, &n);
n = std::min(n, size_t{ MAX_PEX_PEER_COUNT });
tr_peerMgrAddPex(tor, TR_PEER_FROM_PEX, pex, n);
tr_free(pex);
}
tr_variantFree(&val);
}
tr_free(tmp);
if (!loaded)
{
return;
}
uint8_t const* added = nullptr;
auto added_len = size_t{};
if (tr_variantDictFindRaw(&val, TR_KEY_added, &added, &added_len))
{
uint8_t const* added_f = nullptr;
auto added_f_len = size_t{};
if (!tr_variantDictFindRaw(&val, TR_KEY_added_f, &added_f, &added_f_len))
{
added_f_len = 0;
added_f = nullptr;
}
auto n = size_t{};
tr_pex* const pex = tr_peerMgrCompactToPex(added, added_len, added_f, added_f_len, &n);
n = std::min(n, size_t{ MAX_PEX_PEER_COUNT });
tr_peerMgrAddPex(tor, TR_PEER_FROM_PEX, pex, n);
tr_free(pex);
}
if (tr_variantDictFindRaw(&val, TR_KEY_added6, &added, &added_len))
{
uint8_t const* added_f = nullptr;
auto added_f_len = size_t{};
if (!tr_variantDictFindRaw(&val, TR_KEY_added6_f, &added_f, &added_f_len))
{
added_f_len = 0;
added_f = nullptr;
}
auto n = size_t{};
tr_pex* const pex = tr_peerMgrCompact6ToPex(added, added_len, added_f, added_f_len, &n);
n = std::min(n, size_t{ MAX_PEX_PEER_COUNT });
tr_peerMgrAddPex(tor, TR_PEER_FROM_PEX, pex, n);
tr_free(pex);
}
tr_variantFree(&val);
}
static void sendPex(tr_peerMsgsImpl* msgs);

View File

@ -382,7 +382,7 @@ static uint64_t loadIdleLimits(tr_variant* dict, tr_torrent* tor)
static void saveName(tr_variant* dict, tr_torrent const* tor)
{
tr_variantDictAddStr(dict, TR_KEY_name, tr_torrentName(tor));
tr_variantDictAddStrView(dict, TR_KEY_name, tr_torrentName(tor));
}
static uint64_t loadName(tr_variant* dict, tr_torrent* tor)
@ -424,7 +424,7 @@ static void saveFilenames(tr_variant* dict, tr_torrent const* tor)
for (tr_file_index_t i = 0; i < n; ++i)
{
tr_variantListAddStr(list, files[i].is_renamed ? files[i].name : "");
tr_variantListAddStrView(list, files[i].is_renamed ? files[i].name : "");
}
}
}
@ -465,7 +465,7 @@ static void bitfieldToRaw(tr_bitfield const* b, tr_variant* benc)
}
else if (b->hasAll())
{
tr_variantInitStr(benc, "all"sv);
tr_variantInitStrView(benc, "all"sv);
}
else
{
@ -510,7 +510,7 @@ static void saveProgress(tr_variant* dict, tr_torrent* tor)
/* add the progress */
if (tor->completeness == TR_SEED)
{
tr_variantDictAddStr(prog, TR_KEY_have, "all"sv);
tr_variantDictAddStrView(prog, TR_KEY_have, "all"sv);
}
/* add the blocks bitfield */
@ -691,7 +691,7 @@ void tr_torrentSaveResume(tr_torrent* tor)
tr_variantDictAddInt(&top, TR_KEY_added_date, tor->addedDate);
tr_variantDictAddInt(&top, TR_KEY_corrupt, tor->corruptPrev + tor->corruptCur);
tr_variantDictAddInt(&top, TR_KEY_done_date, tor->doneDate);
tr_variantDictAddStr(&top, TR_KEY_destination, tor->downloadDir);
tr_variantDictAddStrView(&top, TR_KEY_destination, tor->downloadDir);
if (tor->incompleteDir != nullptr)
{
@ -748,15 +748,21 @@ static uint64_t loadFromFile(tr_torrent* tor, uint64_t fieldsToLoad, bool* didRe
}
char* const filename = getResumeFilename(tor, TR_METAINFO_BASENAME_HASH);
if (!tr_variantFromFile(&top, TR_VARIANT_FMT_BENC, filename, &error))
auto buf = std::vector<char>{};
if (!tr_loadFile(buf, filename, &error) ||
!tr_variantFromBuf(
&top,
TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE,
{ std::data(buf), std::size(buf) },
nullptr,
&error))
{
tr_logAddTorDbg(tor, "Couldn't read \"%s\": %s", filename, error->message);
tr_error_clear(&error);
char* old_filename = getResumeFilename(tor, TR_METAINFO_BASENAME_NAME_AND_PARTIAL_HASH);
if (!tr_variantFromFile(&top, TR_VARIANT_FMT_BENC, old_filename, &error))
if (!tr_variantFromFile(&top, TR_VARIANT_PARSE_BENC, old_filename, &error))
{
tr_logAddTorDbg(tor, "Couldn't read \"%s\" either: %s", old_filename, error->message);
tr_error_free(error);

View File

@ -184,7 +184,7 @@ static void handle_upload(struct evhttp_request* req, tr_rpc_server* server)
auto top = tr_variant{};
tr_variantInitDict(&top, 2);
tr_variantDictAddStr(&top, TR_KEY_method, "torrent-add");
tr_variantDictAddStrView(&top, TR_KEY_method, "torrent-add");
auto* const args = tr_variantDictAddDict(&top, TR_KEY_arguments, 2);
tr_variantDictAddBool(args, TR_KEY_paused, paused);
@ -195,7 +195,7 @@ static void handle_upload(struct evhttp_request* req, tr_rpc_server* server)
tr_variantDictAddStrView(args, TR_KEY_filename, body);
have_source = true;
}
else if (tr_variantFromBenc(&test, body) == 0)
else if (tr_variantFromBuf(&test, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, body))
{
auto* b64 = static_cast<char*>(tr_base64_encode(body.c_str(), body_len, nullptr));
tr_variantDictAddStr(args, TR_KEY_metainfo, b64);
@ -458,7 +458,7 @@ static void rpc_response_func(tr_session* /*session*/, tr_variant* response, voi
static void handle_rpc_from_json(struct evhttp_request* req, tr_rpc_server* server, std::string_view json)
{
auto top = tr_variant{};
auto const have_content = tr_variantFromJson(&top, json) == 0;
auto const have_content = tr_variantFromBuf(&top, TR_VARIANT_PARSE_JSON | TR_VARIANT_PARSE_INPLACE, json);
auto* const data = tr_new0(struct rpc_response_data, 1);
data->req = req;

View File

@ -420,9 +420,9 @@ static void addTrackers(tr_info const* info, tr_variant* trackers)
{
tr_tracker_info const* t = &info->trackers[i];
tr_variant* d = tr_variantListAddDict(trackers, 4);
tr_variantDictAddStr(d, TR_KEY_announce, t->announce);
tr_variantDictAddStrView(d, TR_KEY_announce, t->announce);
tr_variantDictAddInt(d, TR_KEY_id, t->id);
tr_variantDictAddStr(d, TR_KEY_scrape, t->scrape);
tr_variantDictAddStrView(d, TR_KEY_scrape, t->scrape);
tr_variantDictAddInt(d, TR_KEY_tier, t->tier);
}
}
@ -542,7 +542,7 @@ static void initField(
break;
case TR_KEY_downloadDir:
tr_variantInitStr(initme, tr_torrentGetDownloadDir(tor));
tr_variantInitStrView(initme, tr_torrentGetDownloadDir(tor));
break;
case TR_KEY_downloadedEver:
@ -562,7 +562,7 @@ static void initField(
break;
case TR_KEY_errorString:
tr_variantInitStr(initme, st->errorString);
tr_variantInitStrView(initme, st->errorString);
break;
case TR_KEY_eta:
@ -584,7 +584,7 @@ static void initField(
break;
case TR_KEY_hashString:
tr_variantInitStr(initme, tor->info.hashString);
tr_variantInitStrView(initme, tor->info.hashString);
break;
case TR_KEY_haveUnchecked:
@ -646,7 +646,7 @@ static void initField(
break;
case TR_KEY_name:
tr_variantInitStr(initme, tr_torrentName(tor));
tr_variantInitStrView(initme, tr_torrentName(tor));
break;
case TR_KEY_percentDone:
@ -697,7 +697,7 @@ static void initField(
}
else
{
tr_variantInitStr(initme, ""sv);
tr_variantInitStrView(initme, ""sv);
}
break;
@ -711,7 +711,7 @@ static void initField(
break;
case TR_KEY_primary_mime_type:
tr_variantInitStr(initme, tr_torrentPrimaryMimeType(tor));
tr_variantInitStrView(initme, tr_torrentPrimaryMimeType(tor));
break;
case TR_KEY_priorities:
@ -2290,7 +2290,7 @@ static void addSessionField(tr_session* s, tr_variant* d, tr_quark key)
break;
case TR_KEY_rpc_version_semver:
tr_variantDictAddStr(d, key, RPC_VERSION_SEMVER);
tr_variantDictAddStrView(d, key, RPC_VERSION_SEMVER);
break;
case TR_KEY_rpc_version_minimum:
@ -2382,7 +2382,7 @@ static void addSessionField(tr_session* s, tr_variant* d, tr_quark key)
break;
case TR_KEY_version:
tr_variantDictAddStr(d, key, LONG_VERSION_STRING);
tr_variantDictAddStrView(d, key, LONG_VERSION_STRING);
break;
case TR_KEY_encryption:

View File

@ -324,7 +324,7 @@ void tr_sessionGetDefaultSettings(tr_variant* d)
tr_variantDictReserve(d, 69);
tr_variantDictAddBool(d, TR_KEY_blocklist_enabled, false);
tr_variantDictAddStr(d, TR_KEY_blocklist_url, "http://www.example.com/blocklist"sv);
tr_variantDictAddStrView(d, TR_KEY_blocklist_url, "http://www.example.com/blocklist"sv);
tr_variantDictAddInt(d, TR_KEY_cache_size_mb, DefaultCacheSizeMB);
tr_variantDictAddBool(d, TR_KEY_dht_enabled, true);
tr_variantDictAddBool(d, TR_KEY_utp_enabled, true);
@ -346,7 +346,7 @@ void tr_sessionGetDefaultSettings(tr_variant* d)
tr_variantDictAddBool(d, TR_KEY_peer_port_random_on_start, false);
tr_variantDictAddInt(d, TR_KEY_peer_port_random_low, 49152);
tr_variantDictAddInt(d, TR_KEY_peer_port_random_high, 65535);
tr_variantDictAddStr(d, TR_KEY_peer_socket_tos, TR_DEFAULT_PEER_SOCKET_TOS_STR);
tr_variantDictAddStrView(d, TR_KEY_peer_socket_tos, TR_DEFAULT_PEER_SOCKET_TOS_STR);
tr_variantDictAddBool(d, TR_KEY_pex_enabled, true);
tr_variantDictAddBool(d, TR_KEY_port_forwarding_enabled, true);
tr_variantDictAddInt(d, TR_KEY_preallocation, TR_PREALLOCATE_SPARSE);
@ -358,20 +358,20 @@ void tr_sessionGetDefaultSettings(tr_variant* d)
tr_variantDictAddBool(d, TR_KEY_ratio_limit_enabled, false);
tr_variantDictAddBool(d, TR_KEY_rename_partial_files, true);
tr_variantDictAddBool(d, TR_KEY_rpc_authentication_required, false);
tr_variantDictAddStr(d, TR_KEY_rpc_bind_address, "0.0.0.0");
tr_variantDictAddStrView(d, TR_KEY_rpc_bind_address, "0.0.0.0");
tr_variantDictAddBool(d, TR_KEY_rpc_enabled, false);
tr_variantDictAddStr(d, TR_KEY_rpc_password, "");
tr_variantDictAddStr(d, TR_KEY_rpc_username, "");
tr_variantDictAddStr(d, TR_KEY_rpc_whitelist, TR_DEFAULT_RPC_WHITELIST);
tr_variantDictAddStrView(d, TR_KEY_rpc_password, "");
tr_variantDictAddStrView(d, TR_KEY_rpc_username, "");
tr_variantDictAddStrView(d, TR_KEY_rpc_whitelist, TR_DEFAULT_RPC_WHITELIST);
tr_variantDictAddBool(d, TR_KEY_rpc_whitelist_enabled, true);
tr_variantDictAddStr(d, TR_KEY_rpc_host_whitelist, TR_DEFAULT_RPC_HOST_WHITELIST);
tr_variantDictAddStrView(d, TR_KEY_rpc_host_whitelist, TR_DEFAULT_RPC_HOST_WHITELIST);
tr_variantDictAddBool(d, TR_KEY_rpc_host_whitelist_enabled, true);
tr_variantDictAddInt(d, TR_KEY_rpc_port, TR_DEFAULT_RPC_PORT);
tr_variantDictAddStr(d, TR_KEY_rpc_url, TR_DEFAULT_RPC_URL_STR);
tr_variantDictAddStrView(d, TR_KEY_rpc_url, TR_DEFAULT_RPC_URL_STR);
tr_variantDictAddBool(d, TR_KEY_scrape_paused_torrents_enabled, true);
tr_variantDictAddStr(d, TR_KEY_script_torrent_added_filename, "");
tr_variantDictAddStrView(d, TR_KEY_script_torrent_added_filename, "");
tr_variantDictAddBool(d, TR_KEY_script_torrent_added_enabled, false);
tr_variantDictAddStr(d, TR_KEY_script_torrent_done_filename, "");
tr_variantDictAddStrView(d, TR_KEY_script_torrent_done_filename, "");
tr_variantDictAddBool(d, TR_KEY_script_torrent_done_enabled, false);
tr_variantDictAddInt(d, TR_KEY_seed_queue_size, 10);
tr_variantDictAddBool(d, TR_KEY_seed_queue_enabled, false);
@ -386,8 +386,8 @@ void tr_sessionGetDefaultSettings(tr_variant* d)
tr_variantDictAddBool(d, TR_KEY_speed_limit_up_enabled, false);
tr_variantDictAddInt(d, TR_KEY_umask, 022);
tr_variantDictAddInt(d, TR_KEY_upload_slots_per_torrent, 14);
tr_variantDictAddStr(d, TR_KEY_bind_address_ipv4, TR_DEFAULT_BIND_ADDRESS_IPV4);
tr_variantDictAddStr(d, TR_KEY_bind_address_ipv6, TR_DEFAULT_BIND_ADDRESS_IPV6);
tr_variantDictAddStrView(d, TR_KEY_bind_address_ipv4, TR_DEFAULT_BIND_ADDRESS_IPV4);
tr_variantDictAddStrView(d, TR_KEY_bind_address_ipv6, TR_DEFAULT_BIND_ADDRESS_IPV6);
tr_variantDictAddBool(d, TR_KEY_start_added_torrents, true);
tr_variantDictAddBool(d, TR_KEY_trash_original_torrent_files, false);
tr_variantDictAddInt(d, TR_KEY_anti_brute_force_threshold, 100);
@ -491,7 +491,7 @@ bool tr_sessionLoadSettings(tr_variant* dict, char const* configDir, char const*
auto fileSettings = tr_variant{};
auto const filename = tr_strvPath(configDir, "settings.json"sv);
auto success = bool{};
if (tr_error* error = nullptr; tr_variantFromFile(&fileSettings, TR_VARIANT_FMT_JSON, filename.c_str(), &error))
if (tr_error* error = nullptr; tr_variantFromFile(&fileSettings, TR_VARIANT_PARSE_JSON, filename.c_str(), &error))
{
tr_variantMergeDicts(dict, &fileSettings);
tr_variantFree(&fileSettings);
@ -520,7 +520,7 @@ void tr_sessionSaveSettings(tr_session* session, char const* configDir, tr_varia
{
tr_variant fileSettings;
if (tr_variantFromFile(&fileSettings, TR_VARIANT_FMT_JSON, filename.c_str(), nullptr))
if (tr_variantFromFile(&fileSettings, TR_VARIANT_PARSE_JSON, filename.c_str(), nullptr))
{
tr_variantMergeDicts(&settings, &fileSettings);
tr_variantFree(&fileSettings);

View File

@ -42,12 +42,12 @@ static void loadCumulativeStats(tr_session const* session, tr_session_stats* set
auto top = tr_variant{};
auto filename = getFilename(session);
bool loaded = tr_variantFromFile(&top, TR_VARIANT_FMT_JSON, filename.c_str(), nullptr);
bool loaded = tr_variantFromFile(&top, TR_VARIANT_PARSE_JSON, filename.c_str(), nullptr);
if (!loaded)
{
filename = getOldFilename(session);
loaded = tr_variantFromFile(&top, TR_VARIANT_FMT_BENC, filename.c_str(), nullptr);
loaded = tr_variantFromFile(&top, TR_VARIANT_PARSE_BENC, filename.c_str(), nullptr);
}
if (loaded)

View File

@ -80,13 +80,22 @@ static void clearMetainfo(tr_ctor* ctor)
setSourceFile(ctor, nullptr);
}
static int parseMetainfoContents(tr_ctor* ctor)
{
auto& contents = ctor->contents;
auto sv = std::string_view{ std::data(contents), std::size(contents) };
ctor->isSet_metainfo = tr_variantFromBuf(&ctor->metainfo, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, sv);
return ctor->isSet_metainfo ? 0 : EILSEQ;
}
int tr_ctorSetMetainfo(tr_ctor* ctor, void const* metainfo, size_t len)
{
clearMetainfo(ctor);
auto sv = std::string_view{ static_cast<char const*>(metainfo), len };
auto const err = tr_variantFromBenc(&ctor->metainfo, sv);
ctor->isSet_metainfo = err == 0;
return err;
ctor->contents.resize(len);
std::copy_n(static_cast<char const*>(metainfo), len, std::begin(ctor->contents));
return parseMetainfoContents(ctor);
}
char const* tr_ctorGetSourceFile(tr_ctor const* ctor)
@ -115,13 +124,14 @@ int tr_ctorSetMetainfoFromMagnetLink(tr_ctor* ctor, char const* magnet_link)
int tr_ctorSetMetainfoFromFile(tr_ctor* ctor, char const* filename)
{
clearMetainfo(ctor);
if (!tr_loadFile(ctor->contents, filename, nullptr) || std::empty(ctor->contents))
{
clearMetainfo(ctor);
return EILSEQ;
}
int const err = tr_ctorSetMetainfo(ctor, std::data(ctor->contents), std::size(ctor->contents));
int const err = parseMetainfoContents(ctor);
if (err)
{
clearMetainfo(ctor);

View File

@ -119,7 +119,8 @@ static size_t findInfoDictOffset(tr_torrent const* tor)
if (fileContents != nullptr)
{
auto top = tr_variant{};
if (tr_variantFromBenc(&top, std::string_view{ reinterpret_cast<char const*>(fileContents), fileLen }) == 0)
auto const contents_sv = std::string_view{ reinterpret_cast<char const*>(fileContents), fileLen };
if (tr_variantFromBuf(&top, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, contents_sv))
{
tr_variant* infoDict = nullptr;
if (tr_variantDictFindDict(&top, TR_KEY_info, &infoDict))
@ -276,19 +277,16 @@ void tr_torrentSetMetadataPiece(tr_torrent* tor, int piece, void const* data, in
if (checksumPassed)
{
/* checksum passed; now try to parse it as benc */
tr_variant infoDict;
auto metadata_sv = std::string_view{ m->metadata, m->metadata_size };
int const err = tr_variantFromBenc(&infoDict, metadata_sv);
dbgmsg(tor, "err is %d", err);
metainfoParsed = err == 0;
auto infoDict = tr_variant{};
auto const metadata_sv = std::string_view{ m->metadata, m->metadata_size };
metainfoParsed = tr_variantFromBuf(&infoDict, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, metadata_sv);
if (metainfoParsed)
{
/* yay we have bencoded metainfo... merge it into our .torrent file */
tr_variant newMetainfo;
char* path = tr_strdup(tor->info.torrent);
if (tr_variantFromFile(&newMetainfo, TR_VARIANT_FMT_BENC, path, nullptr))
if (tr_variantFromFile(&newMetainfo, TR_VARIANT_PARSE_BENC, path, nullptr))
{
/* remove any old .torrent and .resume files */
tr_sys_path_remove(path, nullptr);

View File

@ -2566,7 +2566,7 @@ bool tr_torrentSetAnnounceList(tr_torrent* tor, tr_tracker_info const* trackers_
}
/* save to the .torrent file */
if (ok && tr_variantFromFile(&metainfo, TR_VARIANT_FMT_BENC, tor->info.torrent, nullptr))
if (ok && tr_variantFromFile(&metainfo, TR_VARIANT_PARSE_BENC, tor->info.torrent, nullptr))
{
/* remove the old fields */
tr_variantDictRemove(&metainfo, TR_KEY_announce);

View File

@ -315,14 +315,14 @@ int tr_dhtInit(tr_session* ss)
auto const dat_file = tr_strvPath(ss->configDir, "dht.dat"sv);
auto benc = tr_variant{};
int rc = tr_variantFromFile(&benc, TR_VARIANT_FMT_BENC, dat_file.c_str(), nullptr) ? 0 : -1;
auto const ok = tr_variantFromFile(&benc, TR_VARIANT_PARSE_JSON, dat_file.c_str());
bool have_id = false;
uint8_t* nodes = nullptr;
uint8_t* nodes6 = nullptr;
size_t len = 0;
size_t len6 = 0;
if (rc == 0)
if (ok)
{
uint8_t const* raw = nullptr;
have_id = tr_variantDictFindRaw(&benc, TR_KEY_id, &raw, &len);
@ -365,8 +365,7 @@ int tr_dhtInit(tr_session* ss)
tr_rand_buffer(myid, 20);
}
rc = dht_init(ss->udp_socket, ss->udp6_socket, myid, nullptr);
int rc = dht_init(ss->udp_socket, ss->udp6_socket, myid, nullptr);
if (rc < 0)
{
tr_free(nodes6);

View File

@ -20,9 +20,11 @@
#define LIBTRANSMISSION_VARIANT_MODULE
#include "transmission.h"
#include "tr-assert.h"
#include "utils.h" /* tr_snprintf() */
#include "variant.h"
#include "variant-common.h"
#include "variant.h"
using namespace std::literals;
@ -152,8 +154,10 @@ static tr_variant* get_node(std::deque<tr_variant*>& stack, std::optional<tr_qua
* easier to read, but was vulnerable to a smash-stacking
* attack via maliciously-crafted bencoded data. (#667)
*/
int tr_variantParseBenc(tr_variant& top, std::string_view benc, char const** setme_end)
int tr_variantParseBenc(tr_variant& top, int parse_opts, std::string_view benc, char const** setme_end)
{
TR_ASSERT((parse_opts & TR_VARIANT_PARSE_BENC) != 0);
auto stack = std::deque<tr_variant*>{};
auto key = std::optional<tr_quark>{};
@ -252,7 +256,14 @@ int tr_variantParseBenc(tr_variant& top, std::string_view benc, char const** set
tr_variant* const v = get_node(stack, key, &top, &err);
if (v != nullptr)
{
tr_variantInitStr(v, *sv);
if ((parse_opts & TR_VARIANT_PARSE_INPLACE) != 0)
{
tr_variantInitStrView(v, *sv);
}
else
{
tr_variantInitStr(v, *sv);
}
}
}
break;

View File

@ -15,7 +15,9 @@
#include <optional>
#include <string_view>
struct tr_variant;
#include "transmission.h"
#include "variant.h"
using VariantWalkFunc = void (*)(tr_variant const* val, void* user_data);
@ -44,6 +46,6 @@ std::optional<int64_t> tr_bencParseInt(std::string_view* benc_inout);
/** @brief Private function that's exposed here only for unit tests */
std::optional<std::string_view> tr_bencParseStr(std::string_view* benc_inout);
int tr_variantParseBenc(tr_variant& setme, std::string_view benc, char const** setme_end);
int tr_variantParseBenc(tr_variant& setme, int opts, std::string_view benc, char const** setme_end);
int tr_variantParseJson(tr_variant& setme, std::string_view benc, char const** setme_end);
int tr_variantParseJson(tr_variant& setme, int opts, std::string_view benc, char const** setme_end);

View File

@ -27,19 +27,21 @@
#include "variant.h"
#include "variant-common.h"
using namespace std::literals;
/* arbitrary value... this is much deeper than our code goes */
#define MAX_DEPTH 64
struct json_wrapper_data
{
int error;
bool has_content;
tr_variant* top;
char const* key;
size_t keylen;
struct evbuffer* keybuf;
struct evbuffer* strbuf;
std::string_view key;
evbuffer* keybuf;
evbuffer* strbuf;
int error;
std::deque<tr_variant*> stack;
tr_variant* top;
int parse_opts;
/* A very common pattern is for a container's children to be similar,
* e.g. they may all be objects with the same set of keys. So when
@ -63,12 +65,10 @@ static tr_variant* get_node(struct jsonsl_st* jsn)
{
node = tr_variantListAdd(parent);
}
else if (tr_variantIsDict(parent) && data->key != nullptr)
else if (tr_variantIsDict(parent) && !std::empty(data->key))
{
node = tr_variantDictAdd(parent, tr_quark_new(std::string_view{ data->key, data->keylen }));
data->key = nullptr;
data->keylen = 0;
node = tr_variantDictAdd(parent, tr_quark_new(data->key));
data->key = ""sv;
}
return node;
@ -154,7 +154,7 @@ static bool decode_hex_string(char const* in, unsigned int* setme)
return true;
}
static char* extract_escaped_string(char const* in, size_t in_len, size_t* len, struct evbuffer* buf)
static std::string_view extract_escaped_string(char const* in, size_t in_len, struct evbuffer* buf)
{
char const* const in_end = in + in_len;
@ -252,13 +252,12 @@ static char* extract_escaped_string(char const* in, size_t in_len, size_t* len,
}
}
*len = evbuffer_get_length(buf);
return (char*)evbuffer_pullup(buf, -1);
return { (char const*)evbuffer_pullup(buf, -1), evbuffer_get_length(buf) };
}
static char const* extract_string(jsonsl_t jsn, struct jsonsl_state_st* state, size_t* len, struct evbuffer* buf)
static std::pair<std::string_view, bool> extract_string(jsonsl_t jsn, struct jsonsl_state_st* state, struct evbuffer* buf)
{
/* figure out where the string is */
// figure out where the string is
char const* in_begin = jsn->base + state->pos_begin;
if (*in_begin == '"')
{
@ -267,15 +266,13 @@ static char const* extract_string(jsonsl_t jsn, struct jsonsl_state_st* state, s
char const* const in_end = jsn->base + state->pos_cur;
size_t const in_len = in_end - in_begin;
if (memchr(in_begin, '\\', in_len) == nullptr)
{
/* it's not escaped */
*len = in_len;
return in_begin;
return std::make_pair(std::string_view{ in_begin, in_len }, true);
}
return extract_escaped_string(in_begin, in_len, len, buf);
return std::make_pair(extract_escaped_string(in_begin, in_len, buf), false);
}
static void action_callback_POP(
@ -288,15 +285,22 @@ static void action_callback_POP(
if (state->type == JSONSL_T_STRING)
{
auto len = size_t{};
char const* str = extract_string(jsn, state, &len, data->strbuf);
tr_variantInitStr(get_node(jsn), { str, len });
auto const [str, inplace] = extract_string(jsn, state, data->strbuf);
if (inplace && ((data->parse_opts & TR_VARIANT_PARSE_INPLACE) != 0))
{
tr_variantInitStrView(get_node(jsn), str);
}
else
{
tr_variantInitStr(get_node(jsn), str);
}
data->has_content = true;
}
else if (state->type == JSONSL_T_HKEY)
{
data->has_content = true;
data->key = extract_string(jsn, state, &data->keylen, data->keybuf);
auto const [key, inplace] = extract_string(jsn, state, data->keybuf);
data->key = key;
}
else if (state->type == JSONSL_T_LIST || state->type == JSONSL_T_OBJECT)
{
@ -336,8 +340,10 @@ static void action_callback_POP(
}
}
int tr_variantParseJson(tr_variant& setme, std::string_view benc, char const** setme_end)
int tr_variantParseJson(tr_variant& setme, int parse_opts, std::string_view benc, char const** setme_end)
{
TR_ASSERT((parse_opts & TR_VARIANT_PARSE_JSON) != 0);
auto data = json_wrapper_data{};
jsonsl_t jsn = jsonsl_new(MAX_DEPTH);
@ -349,12 +355,13 @@ int tr_variantParseJson(tr_variant& setme, std::string_view benc, char const** s
data.error = 0;
data.has_content = false;
data.key = nullptr;
data.top = &setme;
data.stack = {};
data.key = ""sv;
data.keybuf = evbuffer_new();
data.strbuf = evbuffer_new();
data.parse_opts = parse_opts;
data.preallocGuess = {};
data.stack = {};
data.strbuf = evbuffer_new();
data.top = &setme;
/* parse it */
jsonsl_feed(jsn, static_cast<jsonsl_char_t const*>(std::data(benc)), std::size(benc));

View File

@ -1292,42 +1292,35 @@ int tr_variantToFile(tr_variant const* v, tr_variant_fmt fmt, char const* filena
****
***/
static int tr_variantFromBuf(tr_variant& setme, tr_variant_fmt fmt, std::string_view buf, char const** setme_end)
bool tr_variantFromBuf(tr_variant* setme, int opts, std::string_view buf, char const** setme_end, tr_error** error)
{
/* parse with LC_NUMERIC="C" to ensure a "." decimal separator */
struct locale_context locale_ctx;
// supported formats: benc, json
TR_ASSERT((opts & (TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_JSON)) != 0);
// parse with LC_NUMERIC="C" to ensure a "." decimal separator
auto locale_ctx = locale_context{};
use_numeric_locale(&locale_ctx, "C");
auto err = int{};
switch (fmt)
{
case TR_VARIANT_FMT_JSON:
case TR_VARIANT_FMT_JSON_LEAN:
err = tr_variantParseJson(setme, buf, setme_end);
break;
default /* TR_VARIANT_FMT_BENC */:
err = tr_variantParseBenc(setme, buf, setme_end);
break;
}
auto err = (opts & TR_VARIANT_PARSE_BENC) ? tr_variantParseBenc(*setme, opts, buf, setme_end) :
tr_variantParseJson(*setme, opts, buf, setme_end);
/* restore the previous locale */
restore_locale(&locale_ctx);
return err;
if (err)
{
tr_error_set_literal(error, EILSEQ, "error parsing encoded data");
return false;
}
return true;
}
int tr_variantFromBenc(tr_variant* setme, std::string_view benc, char const** setme_end)
bool tr_variantFromFile(tr_variant* setme, tr_variant_parse_opts opts, char const* filename, tr_error** error)
{
return tr_variantFromBuf(*setme, TR_VARIANT_FMT_BENC, benc, setme_end);
}
// can't do inplace when this function is allocating & freeing the memory...
TR_ASSERT((opts & TR_VARIANT_PARSE_INPLACE) == 0);
int tr_variantFromJson(tr_variant* setme, std::string_view json)
{
return tr_variantFromBuf(*setme, TR_VARIANT_FMT_JSON, json, nullptr);
}
bool tr_variantFromFile(tr_variant* setme, tr_variant_fmt fmt, char const* filename, tr_error** error)
{
auto buf = std::vector<char>{};
if (!tr_loadFile(buf, filename, error))
{
@ -1335,12 +1328,5 @@ bool tr_variantFromFile(tr_variant* setme, tr_variant_fmt fmt, char const* filen
}
auto sv = std::string_view{ std::data(buf), std::size(buf) };
auto const error_code = tr_variantFromBuf(*setme, fmt, sv, nullptr);
if (error_code != 0)
{
tr_error_set_literal(error, error_code, _("Unable to parse file content"));
return false;
}
return true;
return tr_variantFromBuf(setme, opts, sv, nullptr, error);
}

View File

@ -112,12 +112,22 @@ char* tr_variantToStr(tr_variant const* variant, tr_variant_fmt fmt, size_t* len
struct evbuffer* tr_variantToBuf(tr_variant const* variant, tr_variant_fmt fmt);
enum tr_variant_parse_opts
{
TR_VARIANT_PARSE_BENC = (1 << 0),
TR_VARIANT_PARSE_JSON = (1 << 1),
TR_VARIANT_PARSE_INPLACE = (1 << 2)
};
/* TR_VARIANT_FMT_JSON_LEAN and TR_VARIANT_FMT_JSON are equivalent here. */
bool tr_variantFromFile(tr_variant* setme, tr_variant_fmt fmt, char const* filename, struct tr_error** error);
bool tr_variantFromFile(tr_variant* setme, tr_variant_parse_opts opts, char const* filename, struct tr_error** error = nullptr);
int tr_variantFromBenc(tr_variant* setme, std::string_view benc, char const** setme_end = nullptr);
int tr_variantFromJson(tr_variant* setme, std::string_view json);
bool tr_variantFromBuf(
tr_variant* setme,
int variant_parse_opts,
std::string_view buf,
char const** setme_end = nullptr,
tr_error** error = nullptr);
constexpr bool tr_variantIsType(tr_variant const* b, int type)
{

View File

@ -426,7 +426,7 @@ Prefs::~Prefs()
tr_variant file_settings;
QFile const file(QDir(config_dir_).absoluteFilePath(QStringLiteral("settings.json")));
if (!tr_variantFromFile(&file_settings, TR_VARIANT_FMT_JSON, file.fileName().toUtf8().constData(), nullptr))
if (!tr_variantFromFile(&file_settings, TR_VARIANT_PARSE_JSON, file.fileName().toUtf8().constData(), nullptr))
{
tr_variantInitDict(&file_settings, PREFS_COUNT);
}

View File

@ -277,7 +277,7 @@ void RpcClient::networkRequestFinished(QNetworkReply* reply)
TrVariantPtr json = createVariant();
RpcResponse result;
if (tr_variantFromJson(json.get(), json_sv) == 0)
if (tr_variantFromBuf(json.get(), TR_VARIANT_PARSE_JSON, json_sv))
{
result = parseResponseData(*json);
}

View File

@ -48,8 +48,7 @@ TEST_P(JSONTest, testElements)
};
tr_variant top;
int err = tr_variantFromJson(&top, in);
EXPECT_EQ(0, err);
EXPECT_TRUE(tr_variantFromBuf(&top, TR_VARIANT_PARSE_JSON | TR_VARIANT_PARSE_INPLACE, in));
EXPECT_TRUE(tr_variantIsDict(&top));
auto sv = std::string_view{};
@ -78,43 +77,29 @@ TEST_P(JSONTest, testElements)
EXPECT_TRUE(tr_variantDictFindStrView(&top, tr_quark_new("null"sv), &sv));
EXPECT_EQ(""sv, sv);
if (err == 0)
{
tr_variantFree(&top);
}
tr_variantFree(&top);
}
TEST_P(JSONTest, testUtf8)
{
auto in = std::string{ "{ \"key\": \"Letöltések\" }" };
auto in = "{ \"key\": \"Letöltések\" }"sv;
tr_variant top;
auto sv = std::string_view{};
char* json;
int err;
tr_quark const key = tr_quark_new("key"sv);
err = tr_variantFromJson(&top, in);
EXPECT_EQ(0, err);
EXPECT_TRUE(tr_variantFromBuf(&top, TR_VARIANT_PARSE_JSON | TR_VARIANT_PARSE_INPLACE, in));
EXPECT_TRUE(tr_variantIsDict(&top));
EXPECT_TRUE(tr_variantDictFindStrView(&top, key, &sv));
EXPECT_EQ("Letöltések"sv, sv);
tr_variantFree(&top);
if (err == 0)
{
tr_variantFree(&top);
}
in = std::string{ R"({ "key": "\u005C" })" };
err = tr_variantFromJson(&top, in);
EXPECT_EQ(0, err);
in = R"({ "key": "\u005C" })"sv;
EXPECT_TRUE(tr_variantFromBuf(&top, TR_VARIANT_PARSE_JSON | TR_VARIANT_PARSE_INPLACE, in));
EXPECT_TRUE(tr_variantIsDict(&top));
EXPECT_TRUE(tr_variantDictFindStrView(&top, key, &sv));
EXPECT_EQ("\\"sv, sv);
if (err == 0)
{
tr_variantFree(&top);
}
tr_variantFree(&top);
/**
* 1. Feed it JSON-escaped nonascii to the JSON decoder.
@ -124,32 +109,22 @@ TEST_P(JSONTest, testUtf8)
* 5. Dogfood that result back into the parser.
* 6. Confirm that the result is UTF-8.
*/
in = std::string{ R"({ "key": "Let\u00f6lt\u00e9sek" })" };
err = tr_variantFromJson(&top, in);
EXPECT_EQ(0, err);
in = R"({ "key": "Let\u00f6lt\u00e9sek" })"sv;
EXPECT_TRUE(tr_variantFromBuf(&top, TR_VARIANT_PARSE_JSON | TR_VARIANT_PARSE_INPLACE, in));
EXPECT_TRUE(tr_variantIsDict(&top));
EXPECT_TRUE(tr_variantDictFindStrView(&top, key, &sv));
EXPECT_EQ("Letöltések"sv, sv);
json = tr_variantToStr(&top, TR_VARIANT_FMT_JSON, nullptr);
if (err == 0)
{
tr_variantFree(&top);
}
tr_variantFree(&top);
EXPECT_NE(nullptr, json);
EXPECT_NE(nullptr, strstr(json, "\\u00f6"));
EXPECT_NE(nullptr, strstr(json, "\\u00e9"));
err = tr_variantFromJson(&top, json);
EXPECT_EQ(0, err);
EXPECT_TRUE(tr_variantFromBuf(&top, TR_VARIANT_PARSE_JSON | TR_VARIANT_PARSE_INPLACE, json));
EXPECT_TRUE(tr_variantIsDict(&top));
EXPECT_TRUE(tr_variantDictFindStrView(&top, key, &sv));
EXPECT_EQ("Letöltések"sv, sv);
if (err == 0)
{
tr_variantFree(&top);
}
tr_variantFree(&top);
tr_free(json);
}
@ -172,11 +147,10 @@ TEST_P(JSONTest, test1)
};
tr_variant top;
auto const err = tr_variantFromJson(&top, in);
EXPECT_TRUE(tr_variantFromBuf(&top, TR_VARIANT_PARSE_JSON | TR_VARIANT_PARSE_INPLACE, in));
auto sv = std::string_view{};
int64_t i;
EXPECT_EQ(0, err);
EXPECT_TRUE(tr_variantIsDict(&top));
auto* headers = tr_variantDictFind(&top, tr_quark_new("headers"sv));
EXPECT_NE(nullptr, headers);
@ -210,25 +184,21 @@ TEST_P(JSONTest, test2)
auto const in = std::string{ " " };
top.type = 0;
int err = tr_variantFromJson(&top, in);
EXPECT_NE(0, err);
EXPECT_FALSE(tr_variantFromBuf(&top, TR_VARIANT_PARSE_JSON | TR_VARIANT_PARSE_INPLACE, in));
EXPECT_FALSE(tr_variantIsDict(&top));
}
TEST_P(JSONTest, test3)
{
auto const in = std::string{
"{ \"error\": 2,"
" \"errorString\": \"torrent not registered with this tracker 6UHsVW'*C\","
" \"eta\": 262792,"
" \"id\": 25,"
" \"leftUntilDone\": 2275655680 }"
};
auto const
in = "{ \"error\": 2,"
" \"errorString\": \"torrent not registered with this tracker 6UHsVW'*C\","
" \"eta\": 262792,"
" \"id\": 25,"
" \"leftUntilDone\": 2275655680 }"sv;
tr_variant top;
auto const err = tr_variantFromJson(&top, in);
EXPECT_EQ(0, err);
EXPECT_TRUE(tr_variantFromBuf(&top, TR_VARIANT_PARSE_JSON | TR_VARIANT_PARSE_INPLACE, in));
auto sv = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&top, TR_KEY_errorString, &sv));
@ -241,8 +211,7 @@ TEST_P(JSONTest, unescape)
{
tr_variant top;
auto const in = std::string{ R"({ "string-1": "\/usr\/lib" })" };
int const err = tr_variantFromJson(&top, in);
EXPECT_EQ(0, err);
EXPECT_TRUE(tr_variantFromBuf(&top, TR_VARIANT_PARSE_JSON | TR_VARIANT_PARSE_INPLACE, in));
auto sv = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&top, tr_quark_new("string-1"sv), &sv));

View File

@ -87,7 +87,7 @@ TEST_F(RpcTest, sessionGet)
tr_variant request;
tr_variantInitDict(&request, 1);
tr_variantDictAddStr(&request, TR_KEY_method, "session-get");
tr_variantDictAddStrView(&request, TR_KEY_method, "session-get");
tr_variant response;
tr_rpc_request_exec_json(session_, &request, rpc_response_func, &response);
tr_variantFree(&request);

View File

@ -211,16 +211,16 @@ TEST_F(VariantTest, parse)
auto i = int64_t{};
auto val = tr_variant{};
char const* end;
auto err = tr_variantFromBenc(&val, benc, &end);
EXPECT_EQ(0, err);
auto ok = tr_variantFromBuf(&val, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, benc, &end);
EXPECT_TRUE(ok);
EXPECT_TRUE(tr_variantGetInt(&val, &i));
EXPECT_EQ(int64_t(64), i);
EXPECT_EQ(std::data(benc) + std::size(benc), end);
tr_variantFree(&val);
benc = "li64ei32ei16ee"sv;
err = tr_variantFromBenc(&val, benc, &end);
EXPECT_EQ(0, err);
ok = tr_variantFromBuf(&val, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, benc, &end);
EXPECT_TRUE(ok);
EXPECT_EQ(std::data(benc) + std::size(benc), end);
EXPECT_EQ(size_t{ 3 }, tr_variantListSize(&val));
EXPECT_TRUE(tr_variantGetInt(tr_variantListChild(&val, 0), &i));
@ -240,13 +240,12 @@ TEST_F(VariantTest, parse)
end = nullptr;
benc = "lllee"sv;
err = tr_variantFromBenc(&val, benc, &end);
EXPECT_NE(0, err);
ok = tr_variantFromBuf(&val, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, benc, &end);
EXPECT_FALSE(ok);
EXPECT_EQ(nullptr, end);
benc = "le"sv;
err = tr_variantFromBenc(&val, benc, &end);
EXPECT_EQ(0, err);
EXPECT_TRUE(tr_variantFromBuf(&val, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, benc, &end));
EXPECT_EQ(std::data(benc) + std::size(benc), end);
saved = tr_variantToStr(&val, TR_VARIANT_FMT_BENC, &len);
@ -280,14 +279,10 @@ TEST_F(VariantTest, bencParseAndReencode)
{
tr_variant val;
char const* end = nullptr;
auto const err = tr_variantFromBenc(&val, test.benc, &end);
if (!test.is_good)
auto const is_good = tr_variantFromBuf(&val, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, test.benc, &end);
EXPECT_EQ(test.is_good, is_good);
if (is_good)
{
EXPECT_NE(0, err);
}
else
{
EXPECT_EQ(0, err);
EXPECT_EQ(test.benc.data() + test.benc.size(), end);
auto saved_len = size_t{};
auto* saved = tr_variantToStr(&val, TR_VARIANT_FMT_BENC, &saved_len);
@ -305,8 +300,8 @@ TEST_F(VariantTest, bencSortWhenSerializing)
tr_variant val;
char const* end;
auto const err = tr_variantFromBenc(&val, In, &end);
EXPECT_EQ(0, err);
auto const ok = tr_variantFromBuf(&val, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, In, &end);
EXPECT_TRUE(ok);
EXPECT_EQ(std::data(In) + std::size(In), end);
auto len = size_t{};
@ -325,8 +320,8 @@ TEST_F(VariantTest, bencMalformedTooManyEndings)
tr_variant val;
char const* end;
auto const err = tr_variantFromBenc(&val, In, &end);
EXPECT_EQ(0, err);
auto const ok = tr_variantFromBuf(&val, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, In, &end);
EXPECT_TRUE(ok);
EXPECT_EQ(std::data(In) + std::size(ExpectedOut), end);
auto len = size_t{};
@ -342,14 +337,14 @@ TEST_F(VariantTest, bencMalformedNoEnding)
{
auto constexpr In = "l1:a1:b1:c"sv;
tr_variant val;
EXPECT_EQ(EILSEQ, tr_variantFromBenc(&val, In));
EXPECT_FALSE(tr_variantFromBuf(&val, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, In));
}
TEST_F(VariantTest, bencMalformedIncompleteString)
{
auto constexpr In = "1:"sv;
tr_variant val;
EXPECT_EQ(EILSEQ, tr_variantFromBenc(&val, In));
EXPECT_FALSE(tr_variantFromBuf(&val, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, In));
}
TEST_F(VariantTest, bencToJson)
@ -372,7 +367,7 @@ TEST_F(VariantTest, bencToJson)
for (auto const& test : Tests)
{
tr_variant top;
tr_variantFromBenc(&top, test.benc);
tr_variantFromBuf(&top, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, test.benc);
auto len = size_t{};
auto* str = tr_variantToStr(&top, TR_VARIANT_FMT_JSON_LEAN, &len);
@ -399,9 +394,9 @@ TEST_F(VariantTest, merge)
tr_variantDictAddInt(&dest, i1, 1);
tr_variantDictAddInt(&dest, i2, 2);
tr_variantDictAddInt(&dest, i4, -35); /* remains untouched */
tr_variantDictAddStr(&dest, s5, "abc");
tr_variantDictAddStr(&dest, s6, "def");
tr_variantDictAddStr(&dest, s7, "127.0.0.1"); /* remains untouched */
tr_variantDictAddStrView(&dest, s5, "abc");
tr_variantDictAddStrView(&dest, s6, "def");
tr_variantDictAddStrView(&dest, s7, "127.0.0.1"); /* remains untouched */
/* new dictionary, will overwrite items in dest */
tr_variant src;
@ -409,9 +404,9 @@ TEST_F(VariantTest, merge)
tr_variantDictAddInt(&src, i1, 1); /* same value */
tr_variantDictAddInt(&src, i2, 4); /* new value */
tr_variantDictAddInt(&src, i3, 3); /* new key:value */
tr_variantDictAddStr(&src, s5, "abc"); /* same value */
tr_variantDictAddStr(&src, s6, "xyz"); /* new value */
tr_variantDictAddStr(&src, s8, "ghi"); /* new key:value */
tr_variantDictAddStrView(&src, s5, "abc"); /* same value */
tr_variantDictAddStrView(&src, s6, "xyz"); /* new value */
tr_variantDictAddStrView(&src, s8, "ghi"); /* new key:value */
tr_variantMergeDicts(&dest, /*const*/ &src);
@ -447,8 +442,8 @@ TEST_F(VariantTest, stackSmash)
// confirm that it parses
char const* end;
tr_variant val;
auto err = tr_variantFromBenc(&val, in, &end);
EXPECT_EQ(0, err);
auto ok = tr_variantFromBuf(&val, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, in, &end);
EXPECT_TRUE(ok);
EXPECT_EQ(in.data() + in.size(), end);
// confirm that we can serialize it back again

View File

@ -342,7 +342,7 @@ int tr_main(int argc, char* argv[])
printf("%s\n", filename);
if (!tr_variantFromFile(&top, TR_VARIANT_FMT_BENC, filename, &error))
if (!tr_variantFromFile(&top, TR_VARIANT_PARSE_BENC, filename, &error))
{
printf("\tError reading file: %s\n", error->message);
tr_error_free(error);

View File

@ -590,7 +590,7 @@ static void addIdArg(tr_variant* args, char const* id_str, char const* fallback)
if (tr_strcmp0(id_str, "active") == 0)
{
tr_variantDictAddStr(args, TR_KEY_ids, "recently-active"sv);
tr_variantDictAddStrView(args, TR_KEY_ids, "recently-active"sv);
}
else if (strcmp(id_str, "all") != 0)
{
@ -2039,7 +2039,7 @@ static int processResponse(char const* rpcurl, std::string_view response)
TR_PRIsv_ARG(response));
}
if (tr_variantFromJson(&top, response) != 0)
if (!tr_variantFromBuf(&top, TR_VARIANT_PARSE_JSON | TR_VARIANT_PARSE_INPLACE, response))
{
tr_logAddNamedError(MY_NAME, "Unable to parse response \"%" TR_PRIsv "\"", TR_PRIsv_ARG(response));
status |= EXIT_FAILURE;
@ -2281,7 +2281,7 @@ static tr_variant* ensure_sset(tr_variant** sset)
{
*sset = tr_new0(tr_variant, 1);
tr_variantInitDict(*sset, 3);
tr_variantDictAddStr(*sset, TR_KEY_method, "session-set"sv);
tr_variantDictAddStrView(*sset, TR_KEY_method, "session-set"sv);
args = tr_variantDictAddDict(*sset, ARGUMENTS, 0);
}
@ -2300,7 +2300,7 @@ static tr_variant* ensure_tset(tr_variant** tset)
{
*tset = tr_new0(tr_variant, 1);
tr_variantInitDict(*tset, 3);
tr_variantDictAddStr(*tset, TR_KEY_method, "torrent-set"sv);
tr_variantDictAddStrView(*tset, TR_KEY_method, "torrent-set"sv);
args = tr_variantDictAddDict(*tset, ARGUMENTS, 1);
}
@ -2345,7 +2345,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
tadd = tr_new0(tr_variant, 1);
tr_variantInitDict(tadd, 3);
tr_variantDictAddStr(tadd, TR_KEY_method, "torrent-add"sv);
tr_variantDictAddStrView(tadd, TR_KEY_method, "torrent-add"sv);
tr_variantDictAddInt(tadd, TR_KEY_tag, TAG_TORRENT_ADD);
tr_variantDictAddDict(tadd, ARGUMENTS, 0);
break;
@ -2434,7 +2434,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
tr_variant* args;
tr_variant* fields;
tr_variantInitDict(top, 3);
tr_variantDictAddStr(top, TR_KEY_method, "torrent-get"sv);
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-get"sv);
args = tr_variantDictAddDict(top, ARGUMENTS, 0);
fields = tr_variantDictAddList(args, TR_KEY_fields, 0);
@ -2481,20 +2481,20 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
case 941:
tr_variantDictAddInt(top, TR_KEY_tag, TAG_PEERS);
tr_variantListAddStr(fields, "peers"sv);
tr_variantListAddStrView(fields, "peers"sv);
addIdArg(args, id, nullptr);
break;
case 942:
tr_variantDictAddInt(top, TR_KEY_tag, TAG_PIECES);
tr_variantListAddStr(fields, "pieces"sv);
tr_variantListAddStr(fields, "pieceCount"sv);
tr_variantListAddStrView(fields, "pieces"sv);
tr_variantListAddStrView(fields, "pieceCount"sv);
addIdArg(args, id, nullptr);
break;
case 943:
tr_variantDictAddInt(top, TR_KEY_tag, TAG_TRACKERS);
tr_variantListAddStr(fields, "trackerStats"sv);
tr_variantListAddStrView(fields, "trackerStats"sv);
addIdArg(args, id, nullptr);
break;
@ -2569,15 +2569,15 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
break;
case 910:
tr_variantDictAddStr(args, TR_KEY_encryption, "required"sv);
tr_variantDictAddStrView(args, TR_KEY_encryption, "required"sv);
break;
case 911:
tr_variantDictAddStr(args, TR_KEY_encryption, "preferred"sv);
tr_variantDictAddStrView(args, TR_KEY_encryption, "preferred"sv);
break;
case 912:
tr_variantDictAddStr(args, TR_KEY_encryption, "tolerated"sv);
tr_variantDictAddStrView(args, TR_KEY_encryption, "tolerated"sv);
break;
case 'm':
@ -2851,7 +2851,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
tr_variant* args;
tr_variant* top = tr_new0(tr_variant, 1);
tr_variantInitDict(top, 2);
tr_variantDictAddStr(top, TR_KEY_method, "torrent-set-location"sv);
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-set-location"sv);
args = tr_variantDictAddDict(top, ARGUMENTS, 3);
tr_variantDictAddStr(args, TR_KEY_location, optarg);
tr_variantDictAddBool(args, TR_KEY_move, false);
@ -2868,7 +2868,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
{
tr_variant* top = tr_new0(tr_variant, 1);
tr_variantInitDict(top, 2);
tr_variantDictAddStr(top, TR_KEY_method, "session-get"sv);
tr_variantDictAddStrView(top, TR_KEY_method, "session-get"sv);
tr_variantDictAddInt(top, TR_KEY_tag, TAG_SESSION);
status |= flush(rpcurl, &top);
break;
@ -2884,7 +2884,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
{
tr_variant* top = tr_new0(tr_variant, 1);
tr_variantInitDict(top, 2);
tr_variantDictAddStr(top, TR_KEY_method, "torrent-start"sv);
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-start"sv);
addIdArg(tr_variantDictAddDict(top, ARGUMENTS, 1), id, nullptr);
status |= flush(rpcurl, &top);
}
@ -2902,7 +2902,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
{
tr_variant* top = tr_new0(tr_variant, 1);
tr_variantInitDict(top, 2);
tr_variantDictAddStr(top, TR_KEY_method, "torrent-stop"sv);
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-stop"sv);
addIdArg(tr_variantDictAddDict(top, ARGUMENTS, 1), id, nullptr);
status |= flush(rpcurl, &top);
}
@ -2921,7 +2921,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
{
tr_variant* top = tr_new0(tr_variant, 1);
tr_variantInitDict(top, 1);
tr_variantDictAddStr(top, TR_KEY_method, "session-close"sv);
tr_variantDictAddStrView(top, TR_KEY_method, "session-close"sv);
status |= flush(rpcurl, &top);
break;
}
@ -2930,7 +2930,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
{
tr_variant* top = tr_new0(tr_variant, 1);
tr_variantInitDict(top, 1);
tr_variantDictAddStr(top, TR_KEY_method, "blocklist-update"sv);
tr_variantDictAddStrView(top, TR_KEY_method, "blocklist-update"sv);
status |= flush(rpcurl, &top);
break;
}
@ -2939,7 +2939,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
{
tr_variant* top = tr_new0(tr_variant, 1);
tr_variantInitDict(top, 2);
tr_variantDictAddStr(top, TR_KEY_method, "session-stats"sv);
tr_variantDictAddStrView(top, TR_KEY_method, "session-stats"sv);
tr_variantDictAddInt(top, TR_KEY_tag, TAG_STATS);
status |= flush(rpcurl, &top);
break;
@ -2949,7 +2949,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
{
tr_variant* top = tr_new0(tr_variant, 1);
tr_variantInitDict(top, 2);
tr_variantDictAddStr(top, TR_KEY_method, "port-test"sv);
tr_variantDictAddStrView(top, TR_KEY_method, "port-test"sv);
tr_variantDictAddInt(top, TR_KEY_tag, TAG_PORTTEST);
status |= flush(rpcurl, &top);
break;
@ -2967,7 +2967,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
top = tr_new0(tr_variant, 1);
tr_variantInitDict(top, 2);
tr_variantDictAddStr(top, TR_KEY_method, "torrent-reannounce"sv);
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-reannounce"sv);
addIdArg(tr_variantDictAddDict(top, ARGUMENTS, 1), id, nullptr);
status |= flush(rpcurl, &top);
break;
@ -2985,7 +2985,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
top = tr_new0(tr_variant, 1);
tr_variantInitDict(top, 2);
tr_variantDictAddStr(top, TR_KEY_method, "torrent-verify"sv);
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-verify"sv);
addIdArg(tr_variantDictAddDict(top, ARGUMENTS, 1), id, nullptr);
status |= flush(rpcurl, &top);
break;
@ -2997,7 +2997,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
tr_variant* args;
tr_variant* top = tr_new0(tr_variant, 1);
tr_variantInitDict(top, 2);
tr_variantDictAddStr(top, TR_KEY_method, "torrent-remove"sv);
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-remove"sv);
args = tr_variantDictAddDict(top, ARGUMENTS, 2);
tr_variantDictAddBool(args, TR_KEY_delete_local_data, c == 840);
addIdArg(args, id, nullptr);
@ -3010,7 +3010,7 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
tr_variant* args;
tr_variant* top = tr_new0(tr_variant, 1);
tr_variantInitDict(top, 2);
tr_variantDictAddStr(top, TR_KEY_method, "torrent-set-location"sv);
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-set-location"sv);
args = tr_variantDictAddDict(top, ARGUMENTS, 3);
tr_variantDictAddStr(args, TR_KEY_location, optarg);
tr_variantDictAddBool(args, TR_KEY_move, true);

View File

@ -260,8 +260,8 @@ static void doScrape(tr_info const* inf)
tr_variant* files;
bool matched = false;
char const* begin = (char const*)evbuffer_pullup(buf, -1);
if (tr_variantFromBenc(&top, { begin, evbuffer_get_length(buf) }) == 0)
auto sv = std::string_view{ begin, evbuffer_get_length(buf) };
if (tr_variantFromBuf(&top, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, sv))
{
if (tr_variantDictFindDict(&top, TR_KEY_files, &files))
{