diff --git a/libtransmission/session.cc b/libtransmission/session.cc index a0edc4c16..670529d42 100644 --- a/libtransmission/session.cc +++ b/libtransmission/session.cc @@ -2026,7 +2026,7 @@ static void sessionLoadTorrents(void* vdata) tr_ctorSetSave(data->ctor, false); /* since we already have them */ tr_sys_path_info info; - char const* dirname = tr_getTorrentDir(data->session); + char const* const dirname = tr_getTorrentDir(data->session); tr_sys_dir_t odir = (tr_sys_path_get_info(dirname, 0, &info, nullptr) && info.type == TR_SYS_PATH_IS_DIRECTORY) ? tr_sys_dir_open(dirname, nullptr) : TR_BAD_SYS_DIR; @@ -2034,20 +2034,22 @@ static void sessionLoadTorrents(void* vdata) auto torrents = std::list{}; if (odir != TR_BAD_SYS_DIR) { - char const* name = nullptr; auto const dirname_sv = std::string_view{ dirname }; auto path = std::string{}; + + char const* name = nullptr; while ((name = tr_sys_dir_read_name(odir, nullptr)) != nullptr) { - if (tr_str_has_suffix(name, ".torrent")) + if (!tr_str_has_suffix(name, ".torrent")) { - tr_buildBuf(path, dirname_sv, "/", name); - tr_ctorSetMetainfoFromFile(data->ctor, path.c_str(), nullptr); + continue; + } - if (tr_torrent* const tor = tr_torrentNew(data->ctor, nullptr); tor != nullptr) - { - torrents.push_back(tor); - } + tr_buildBuf(path, dirname_sv, "/", name); + tr_ctorSetMetainfoFromFile(data->ctor, path.c_str(), nullptr); + if (tr_torrent* const tor = tr_torrentNew(data->ctor, nullptr); tor != nullptr) + { + torrents.push_back(tor); } } diff --git a/libtransmission/torrent-metainfo.cc b/libtransmission/torrent-metainfo.cc index b8c640c7a..c51b22def 100644 --- a/libtransmission/torrent-metainfo.cc +++ b/libtransmission/torrent-metainfo.cc @@ -313,7 +313,7 @@ static bool appendSanitizedComponent(std::string& out, std::string_view in, bool auto constexpr ensure_legal_char = [](auto ch) { auto constexpr Banned = std::string_view{ "<>:\"/\\|?*" }; - auto const banned = Banned.find(ch) != Banned.npos || (unsigned char)ch < 0x20; + auto const banned = Banned.find(ch) != std::string_view::npos || (unsigned char)ch < 0x20; return banned ? '_' : ch; }; auto const old_out_len = std::size(out); @@ -350,7 +350,7 @@ std::string tr_torrent_metainfo::parsePath(std::string_view root, tr_variant* pa } buf = root; - for (int i = 0, n = tr_variantListSize(path); i < n; i++) + for (size_t i = 0, n = tr_variantListSize(path); i < n; ++i) { auto raw = std::string_view{}; if (!tr_variantGetStrView(tr_variantListChild(path, i), &raw)) @@ -470,8 +470,7 @@ std::string_view tr_torrent_metainfo::parseAnnounce(tr_torrent_metainfo& setme, // announce-list // example: d['announce-list'] = [ [tracker1], [backup1], [backup2] ] - tr_variant* tiers = nullptr; - if (tr_variantDictFindList(meta, TR_KEY_announce_list, &tiers)) + if (tr_variant* tiers = nullptr; tr_variantDictFindList(meta, TR_KEY_announce_list, &tiers)) { for (size_t i = 0, n_tiers = tr_variantListSize(tiers); i < n_tiers; ++i) { @@ -561,88 +560,59 @@ std::string_view tr_torrent_metainfo::parseImpl(tr_torrent_metainfo& setme, tr_v } // comment (optional) + setme.comment_.clear(); if (tr_variantDictFindStrView(meta, TR_KEY_comment_utf_8, &sv) || tr_variantDictFindStrView(meta, TR_KEY_comment, &sv)) { setme.comment_ = tr_strvUtf8Clean(sv); } - else - { - setme.comment_.clear(); - } // created by (optional) + setme.creator_.clear(); if (tr_variantDictFindStrView(meta, TR_KEY_created_by_utf_8, &sv) || tr_variantDictFindStrView(meta, TR_KEY_created_by, &sv)) { setme.creator_ = tr_strvUtf8Clean(sv); } - else - { - setme.creator_.clear(); - } // creation date (optional) - if (tr_variantDictFindInt(meta, TR_KEY_creation_date, &i)) - { - setme.date_created_ = i; - } - else - { - setme.date_created_ = 0; - } + setme.date_created_ = tr_variantDictFindInt(meta, TR_KEY_creation_date, &i) ? i : 0; // private (optional) - if (tr_variantDictFindInt(info_dict, TR_KEY_private, &i) || tr_variantDictFindInt(meta, TR_KEY_private, &i)) - { - setme.is_private_ = i != 0; - } - else - { - setme.is_private_ = false; - } + setme.is_private_ = (tr_variantDictFindInt(info_dict, TR_KEY_private, &i) || + tr_variantDictFindInt(meta, TR_KEY_private, &i)) && + (i != 0); // source (optional) + setme.source_.clear(); if (tr_variantDictFindStrView(info_dict, TR_KEY_source, &sv) || tr_variantDictFindStrView(meta, TR_KEY_source, &sv)) { setme.source_ = tr_strvUtf8Clean(sv); } - else - { - setme.source_.clear(); - } // piece length - auto piece_size = uint64_t{}; - if (tr_variantDictFindInt(info_dict, TR_KEY_piece_length, &i) && (i > 0)) - { - piece_size = i; - } - else + if (!tr_variantDictFindInt(info_dict, TR_KEY_piece_length, &i) && (i <= 0)) { return "'info' dict 'piece length' is missing or has an invalid value"; } + auto const piece_size = i; // pieces - if (tr_variantDictFindStrView(info_dict, TR_KEY_pieces, &sv) && (std::size(sv) % sizeof(tr_sha1_digest_t) == 0)) - { - auto const n = std::size(sv) / sizeof(tr_sha1_digest_t); - setme.pieces_.resize(n); - std::copy_n(std::data(sv), std::size(sv), reinterpret_cast(std::data(setme.pieces_))); - } - else + if (!tr_variantDictFindStrView(info_dict, TR_KEY_pieces, &sv) || (std::size(sv) % sizeof(tr_sha1_digest_t) != 0)) { return "'info' dict 'pieces' is missing or has an invalid value"; } + auto const n = std::size(sv) / sizeof(tr_sha1_digest_t); + setme.pieces_.resize(n); + std::copy_n(std::data(sv), std::size(sv), reinterpret_cast(std::data(setme.pieces_))); // files auto total_size = uint64_t{ 0 }; - auto const errstr = parseFiles(setme, info_dict, &total_size); - if (!std::empty(errstr)) + if (auto const errstr = parseFiles(setme, info_dict, &total_size); !std::empty(errstr)) { return errstr; } - if (std::empty(setme.files_) || total_size == 0) + if (std::empty(setme.files_)) { return "no files found"sv; } diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index 22244e298..db32b2c7a 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -773,7 +773,7 @@ tr_torrent* tr_torrentNew(tr_ctor const* ctor, tr_torrent** setme_duplicate_of) auto* const session = tr_ctorGetSession(ctor); TR_ASSERT(tr_isSession(session)); - // is the metainfo valid + // is the metainfo valid? auto top = tr_variant{}; if (!tr_variantFromBuf(&top, TR_VARIANT_PARSE_BENC, tr_ctorGetContents(ctor), nullptr, nullptr)) { @@ -786,9 +786,8 @@ tr_torrent* tr_torrentNew(tr_ctor const* ctor, tr_torrent** setme_duplicate_of) return nullptr; } - // is it a duplicate - auto* const duplicate_of = session->getTorrent(parsed->info.hash); - if (duplicate_of != nullptr) + // is it a duplicate? + if (auto* const duplicate_of = session->getTorrent(parsed->info.hash); duplicate_of != nullptr) { if (setme_duplicate_of != nullptr) { diff --git a/qt/AddData.cc b/qt/AddData.cc index ad0b78b4e..21f48f0b7 100644 --- a/qt/AddData.cc +++ b/qt/AddData.cc @@ -25,13 +25,12 @@ namespace QString getNameFromMetainfo(QByteArray const& benc) { auto metainfo = tr_torrent_metainfo{}; - if (metainfo.parseBenc({ benc.constData(), size_t(benc.size()) })) + if (!metainfo.parseBenc({ benc.constData(), size_t(benc.size()) })) { - auto const& mname = metainfo.name(); - return QString::fromUtf8(std::data(mname), std::size(mname)); + return {}; } - return {}; + return QString::fromStdString(metainfo.name()); } } // namespace diff --git a/qt/OptionsDialog.cc b/qt/OptionsDialog.cc index c6aee9eb5..96eede36a 100644 --- a/qt/OptionsDialog.cc +++ b/qt/OptionsDialog.cc @@ -185,7 +185,7 @@ void OptionsDialog::reload() if (metainfo_) { - size_t i = 0; + int i = 0; auto const n_files = std::size(metainfo_->files()); priorities_.assign(n_files, TR_PRI_NORMAL); wanted_.assign(n_files, true); @@ -198,7 +198,7 @@ void OptionsDialog::reload() f.wanted = wanted_[i]; f.size = file.length(); f.have = 0; - f.filename = QString::fromUtf8(std::data(file.path()), std::size(file.path())); + f.filename = QString::fromStdString(file.path()); files_.push_back(f); ++i; diff --git a/utils/show.cc b/utils/show.cc index a256a8636..bd5af59e7 100644 --- a/utils/show.cc +++ b/utils/show.cc @@ -50,13 +50,16 @@ auto options = std::array{ { 0, nullptr, nullptr, nullptr, false, nullptr } } }; -auto filename_opt = std::string_view{}; -auto magnet_opt = bool{ false }; -auto scrape_opt = bool{ false }; -auto show_version_opt = bool{ false }; -auto unsorted_opt = bool{ false }; +struct app_opts +{ + std::string_view filename; + bool scrape = false; + bool show_magnet = false; + bool show_version = false; + bool unsorted = false; +}; -int parseCommandLine(int argc, char const* const* argv) +int parseCommandLine(app_opts& opts, int argc, char const* const* argv) { int c; char const* optarg; @@ -66,23 +69,23 @@ int parseCommandLine(int argc, char const* const* argv) switch (c) { case 'm': - magnet_opt = true; + opts.show_magnet = true; break; case 's': - scrape_opt = true; + opts.scrape = true; break; case 'u': - unsorted_opt = true; + opts.unsorted = true; break; case 'V': - show_version_opt = true; + opts.show_version = true; break; case TR_OPT_UNK: - filename_opt = optarg; + opts.filename = optarg; break; default: @@ -107,7 +110,7 @@ auto toString(time_t timestamp) return std::string{ std::data(buf) }; } -void showInfo(tr_torrent_metainfo const& metainfo) +void showInfo(app_opts const& opts, tr_torrent_metainfo const& metainfo) { auto buf = std::array{}; @@ -159,8 +162,7 @@ void showInfo(tr_torrent_metainfo const& metainfo) *** **/ - auto const& webseeds = metainfo.webseeds(); - if (!std::empty(webseeds)) + if (auto const& webseeds = metainfo.webseeds(); !std::empty(webseeds)) { printf("\nWEBSEEDS\n\n"); @@ -186,7 +188,7 @@ void showInfo(tr_torrent_metainfo const& metainfo) filenames.emplace_back(filename); } - if (!unsorted_opt) + if (!opts.unsorted) { std::sort(std::begin(filenames), std::end(filenames)); } @@ -219,6 +221,9 @@ CURL* tr_curl_easy_init(struct evbuffer* writebuf) void doScrape(tr_torrent_metainfo const& metainfo) { + auto* const buf = evbuffer_new(); + auto* const curl = tr_curl_easy_init(buf); + for (auto const& tracker : metainfo.announceList()) { if (std::empty(tracker.scrape_str)) @@ -239,80 +244,69 @@ void doScrape(tr_torrent_metainfo const& metainfo) printf("%" TR_PRIsv " ... ", TR_PRIsv_ARG(url)); fflush(stdout); - auto* const buf = evbuffer_new(); - auto* const curl = tr_curl_easy_init(buf); + // execute the http scrape curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_TIMEOUT, TimeoutSecs); - auto const res = curl_easy_perform(curl); if (res != CURLE_OK) { printf("error: %s\n", curl_easy_strerror(res)); + continue; } - else + + // check the response code + long response; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); + if (response != 200 /*HTTP OK*/) { - long response; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); + printf("error: unexpected response %ld \"%s\"\n", response, tr_webGetResponseStr(response)); + continue; + } - if (response != 200) + // print it out + tr_variant top; + char const* begin = (char const*)evbuffer_pullup(buf, -1); + auto sv = std::string_view{ begin, evbuffer_get_length(buf) }; + if (!tr_variantFromBuf(&top, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, sv)) + { + printf("error parsing scrape response\n"); + continue; + } + + bool matched = false; + tr_variant* files = nullptr; + if (tr_variantDictFindDict(&top, TR_KEY_files, &files)) + { + size_t child_pos = 0; + tr_quark key; + tr_variant* val; + + auto hashsv = std::string_view{ reinterpret_cast(std::data(metainfo.infoHash())), + std::size(metainfo.infoHash()) }; + + while (tr_variantDictChild(files, child_pos++, &key, &val)) { - printf("error: unexpected response %ld \"%s\"\n", response, tr_webGetResponseStr(response)); - } - else /* HTTP OK */ - { - tr_variant top; - tr_variant* files; - bool matched = false; - char const* begin = (char const*)evbuffer_pullup(buf, -1); - auto sv = std::string_view{ begin, evbuffer_get_length(buf) }; - if (tr_variantFromBuf(&top, TR_VARIANT_PARSE_BENC | TR_VARIANT_PARSE_INPLACE, sv)) + if (hashsv == tr_quark_get_string_view(key)) { - if (tr_variantDictFindDict(&top, TR_KEY_files, &files)) - { - size_t child_pos = 0; - tr_quark key; - tr_variant* val; - - auto hashsv = std::string_view{ reinterpret_cast(std::data(metainfo.infoHash())), - std::size(metainfo.infoHash()) }; - - while (tr_variantDictChild(files, child_pos, &key, &val)) - { - if (hashsv == tr_quark_get_string_view(key)) - { - int64_t seeders; - if (!tr_variantDictFindInt(val, TR_KEY_complete, &seeders)) - { - seeders = -1; - } - - int64_t leechers; - if (!tr_variantDictFindInt(val, TR_KEY_incomplete, &leechers)) - { - leechers = -1; - } - - printf("%d seeders, %d leechers\n", (int)seeders, (int)leechers); - matched = true; - } - - ++child_pos; - } - } - - tr_variantFree(&top); - } - - if (!matched) - { - printf("no match\n"); + auto i = int64_t{}; + auto const seeders = tr_variantDictFindInt(val, TR_KEY_complete, &i) ? int(i) : -1; + auto const leechers = tr_variantDictFindInt(val, TR_KEY_incomplete, &i) ? int(i) : -1; + printf("%d seeders, %d leechers\n", (int)seeders, (int)leechers); + matched = true; } } } - curl_easy_cleanup(curl); - evbuffer_free(buf); + tr_variantFree(&top); + + if (!matched) + { + printf("no match\n"); + } } + + curl_easy_cleanup(curl); + evbuffer_free(buf); } } // namespace @@ -324,19 +318,20 @@ int tr_main(int argc, char* argv[]) tr_formatter_size_init(DISK_K, DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR); tr_formatter_speed_init(SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR); - if (parseCommandLine(argc, (char const* const*)argv) != 0) + auto opts = app_opts{}; + if (parseCommandLine(opts, argc, (char const* const*)argv) != 0) { return EXIT_FAILURE; } - if (show_version_opt) + if (opts.show_version) { fprintf(stderr, "%s %s\n", MyName, LONG_VERSION_STRING); return EXIT_SUCCESS; } /* make sure the user specified a filename */ - if (std::empty(filename_opt)) + if (std::empty(opts.filename)) { fprintf(stderr, "ERROR: No .torrent file specified.\n"); tr_getopt_usage(MyName, Usage, std::data(options)); @@ -347,13 +342,13 @@ int tr_main(int argc, char* argv[]) /* try to parse the .torrent file */ auto metainfo = tr_torrent_metainfo{}; tr_error* error = nullptr; - auto const parsed = metainfo.parseTorrentFile(filename_opt, nullptr, &error); + auto const parsed = metainfo.parseTorrentFile(opts.filename, nullptr, &error); if (error != nullptr) { fprintf( stderr, "Error parsing .torrent file \"%" TR_PRIsv "\": %s (%d)\n", - TR_PRIsv_ARG(filename_opt), + TR_PRIsv_ARG(opts.filename), error->message, error->code); tr_error_clear(&error); @@ -363,24 +358,24 @@ int tr_main(int argc, char* argv[]) return EXIT_FAILURE; } - if (magnet_opt) + if (opts.show_magnet) { printf("%s", metainfo.magnet().c_str()); } else { printf("Name: %s\n", metainfo.name().c_str()); - printf("File: %" TR_PRIsv "\n", TR_PRIsv_ARG(filename_opt)); + printf("File: %" TR_PRIsv "\n", TR_PRIsv_ARG(opts.filename)); printf("\n"); fflush(stdout); - if (scrape_opt) + if (opts.scrape) { doScrape(metainfo); } else { - showInfo(metainfo); + showInfo(opts, metainfo); } }