refactor: use std::string in tr_file (#2382)

This commit is contained in:
Charles Kerr 2022-01-08 12:53:35 -06:00 committed by GitHub
parent 0c16c454ba
commit 8b65b660c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 138 additions and 146 deletions

View File

@ -53,9 +53,12 @@ void tr_file_piece_map::reset(tr_block_info const& block_info, uint64_t const* f
void tr_file_piece_map::reset(tr_info const& info)
{
tr_file_index_t const n = info.fileCount;
auto const n = info.fileCount();
auto file_sizes = std::vector<uint64_t>(n);
std::transform(info.files, info.files + n, std::begin(file_sizes), [](tr_file const& file) { return file.length; });
for (tr_file_index_t i = 0; i < n; ++i)
{
file_sizes[i] = info.fileSize(i);
}
reset({ info.totalSize, info.pieceSize }, std::data(file_sizes), std::size(file_sizes));
}

View File

@ -123,7 +123,7 @@ static int readOrWriteBytes(
if (!tr_sys_file_read_at(fd, buf, buflen, file_offset, nullptr, &error))
{
err = error->code;
tr_logAddTorErr(tor, "read failed for \"%s\": %s", tor->fileSubpath(file_index), error->message);
tr_logAddTorErr(tor, "read failed for \"%s\": %s", tor->fileSubpath(file_index).c_str(), error->message);
tr_error_free(error);
}
}
@ -132,7 +132,7 @@ static int readOrWriteBytes(
if (!tr_sys_file_write_at(fd, buf, buflen, file_offset, nullptr, &error))
{
err = error->code;
tr_logAddTorErr(tor, "write failed for \"%s\": %s", tor->fileSubpath(file_index), error->message);
tr_logAddTorErr(tor, "write failed for \"%s\": %s", tor->fileSubpath(file_index).c_str(), error->message);
tr_error_free(error);
}
}

View File

@ -110,11 +110,11 @@ bool tr_metainfoAppendSanitizedPathComponent(std::string& out, std::string_view
return std::size(out) > original_out_len;
}
static bool getfile(char** setme, std::string_view root, tr_variant* path, std::string& buf)
static bool getfile(std::string* setme, std::string_view root, tr_variant* path, std::string& buf)
{
bool success = false;
*setme = nullptr;
setme->clear();
if (tr_variantIsList(path))
{
@ -148,7 +148,7 @@ static bool getfile(char** setme, std::string_view root, tr_variant* path, std::
if (success)
{
*setme = tr_utf8clean(buf);
*setme = tr_strvUtf8Clean(buf);
}
return success;
@ -173,10 +173,9 @@ static char const* parseFiles(tr_info* inf, tr_variant* files, tr_variant const*
errstr = nullptr;
inf->isFolder = true;
inf->fileCount = tr_variantListSize(files);
inf->files = tr_new0(tr_file, inf->fileCount);
for (tr_file_index_t i = 0; i < inf->fileCount; i++)
tr_file_index_t const n = tr_variantListSize(files);
inf->files.resize(n);
for (tr_file_index_t i = 0; i < n; ++i)
{
auto* const file = tr_variantListChild(files, i);
@ -193,7 +192,7 @@ static char const* parseFiles(tr_info* inf, tr_variant* files, tr_variant const*
break;
}
if (!getfile(&inf->files[i].name, root_name, path, buf))
if (!getfile(&inf->files[i].subpath, root_name, path, buf))
{
errstr = "path";
break;
@ -205,17 +204,16 @@ static char const* parseFiles(tr_info* inf, tr_variant* files, tr_variant const*
break;
}
inf->files[i].length = len;
inf->files[i].size = len;
inf->totalSize += len;
}
}
else if (tr_variantGetInt(length, &len)) /* single-file mode */
{
inf->isFolder = false;
inf->fileCount = 1;
inf->files = tr_new0(tr_file, 1);
inf->files[0].name = tr_strvDup(root_name);
inf->files[0].length = len;
inf->files.resize(1);
inf->files[0].subpath = root_name;
inf->files[0].size = len;
inf->totalSize += len;
}
else
@ -287,7 +285,7 @@ static char* fix_webseed_url(tr_info const* inf, std::string_view url)
return nullptr;
}
if (inf->fileCount > 1 && !std::empty(url) && url.back() != '/')
if (inf->fileCount() > 1 && !std::empty(url) && url.back() != '/')
{
return tr_strvDup(tr_strvJoin(url, "/"sv));
}
@ -500,7 +498,7 @@ static char const* tr_metainfoParseImpl(
return errstr;
}
if (inf->fileCount == 0 || inf->totalSize == 0)
if (inf->fileCount() == 0 || inf->totalSize == 0)
{
return "files";
}
@ -553,17 +551,8 @@ void tr_metainfoFree(tr_info* inf)
}
}
if (inf->files != nullptr)
{
for (tr_file_index_t ff = 0; ff < inf->fileCount; ff++)
{
tr_free(inf->files[ff].name);
}
}
tr_free(inf->comment);
tr_free(inf->creator);
tr_free(inf->files);
tr_free(inf->name);
tr_free(inf->source);
tr_free(inf->torrent);
@ -571,7 +560,6 @@ void tr_metainfoFree(tr_info* inf)
inf->comment = nullptr;
inf->creator = nullptr;
inf->files = nullptr;
inf->name = nullptr;
inf->source = nullptr;
inf->torrent = nullptr;

View File

@ -106,7 +106,7 @@ std::string_view tr_ctorGetContents(tr_ctor const* ctor)
char const* tr_ctorGetSourceFile(tr_ctor const* ctor)
{
return ctor->metainfo.parsedTorrentFile().c_str();
return ctor->metainfo.torrentFile().c_str();
}
bool tr_ctorSaveContents(tr_ctor const* ctor, std::string_view filename, tr_error** error)
@ -298,7 +298,7 @@ bool tr_ctorGetIncompleteDir(tr_ctor const* ctor, char const** setme)
tr_torrent_metainfo const* tr_ctorGetMetainfo(tr_ctor const* ctor)
{
return std::empty(ctor->metainfo.files()) ? nullptr : &ctor->metainfo;
return !std::empty(ctor->metainfo) ? &ctor->metainfo : nullptr;
}
tr_session* tr_ctorGetSession(tr_ctor const* ctor)

View File

@ -163,46 +163,46 @@ void* tr_torrentGetMetadataPiece(tr_torrent* tor, int piece, size_t* len)
TR_ASSERT(piece >= 0);
TR_ASSERT(len != nullptr);
char* ret = nullptr;
if (tor->hasMetadata())
if (!tor->hasMetadata())
{
ensureInfoDictOffsetIsCached(tor);
return nullptr;
}
auto const info_dict_length = tor->infoDictLength();
TR_ASSERT(info_dict_length > 0);
auto const fd = tr_sys_file_open(tor->torrentFile(), TR_SYS_FILE_READ, 0, nullptr);
if (fd == TR_BAD_SYS_FILE)
{
return nullptr;
}
auto const fd = tr_sys_file_open(tor->torrentFile(), TR_SYS_FILE_READ, 0, nullptr);
if (fd != TR_BAD_SYS_FILE)
ensureInfoDictOffsetIsCached(tor);
auto const info_dict_length = tor->infoDictLength();
TR_ASSERT(info_dict_length > 0);
char* ret = nullptr;
if (size_t o = piece * METADATA_PIECE_SIZE; tr_sys_file_seek(fd, tor->infoDictOffset + o, TR_SEEK_SET, nullptr, nullptr))
{
size_t const l = o + METADATA_PIECE_SIZE <= info_dict_length ? METADATA_PIECE_SIZE : info_dict_length - o;
if (0 < l && l <= METADATA_PIECE_SIZE)
{
size_t const o = piece * METADATA_PIECE_SIZE;
char* buf = tr_new(char, l);
auto n = uint64_t{};
if (tr_sys_file_seek(fd, tor->infoDictOffset + o, TR_SEEK_SET, nullptr, nullptr))
if (tr_sys_file_read(fd, buf, l, &n, nullptr) && n == l)
{
size_t const l = o + METADATA_PIECE_SIZE <= info_dict_length ? METADATA_PIECE_SIZE : info_dict_length - o;
if (0 < l && l <= METADATA_PIECE_SIZE)
{
char* buf = tr_new(char, l);
auto n = uint64_t{};
if (tr_sys_file_read(fd, buf, l, &n, nullptr) && n == l)
{
*len = l;
ret = buf;
buf = nullptr;
}
tr_free(buf);
}
*len = l;
ret = buf;
buf = nullptr;
}
tr_sys_file_close(fd, nullptr);
tr_free(buf);
}
}
TR_ASSERT(ret == nullptr || *len > 0);
tr_sys_file_close(fd, nullptr);
TR_ASSERT(ret == nullptr || *len > 0);
return ret;
}

View File

@ -24,11 +24,6 @@ struct tr_info;
struct tr_torrent_metainfo : public tr_magnet_metainfo
{
[[nodiscard]] constexpr auto const& blockInfo() const
{
return block_info_;
}
public:
tr_torrent_metainfo() = default;
~tr_torrent_metainfo() override = default;
@ -48,6 +43,11 @@ public:
/// BLOCK INFO
[[nodiscard]] constexpr auto const& blockInfo() const
{
return block_info_;
}
[[nodiscard]] constexpr auto blockCount() const
{
return blockInfo().blockCount();
@ -114,9 +114,17 @@ public:
return source_;
}
auto const& files() const
auto fileCount() const
{
return files_;
return std::size(files_);
}
std::string const& fileSubpath(tr_file_index_t i) const
{
return files_.at(i).path();
}
auto fileSize(tr_file_index_t i) const
{
return files_.at(i).size();
}
[[nodiscard]] auto const& isPrivate() const
@ -124,7 +132,7 @@ public:
return is_private_;
}
[[nodiscard]] auto const& parsedTorrentFile() const
[[nodiscard]] auto const& torrentFile() const
{
return torrent_file_;
}
@ -165,20 +173,20 @@ private:
{
return path_;
}
uint64_t length() const
uint64_t size() const
{
return length_;
return size_;
}
file_t(std::string_view path, uint64_t length)
file_t(std::string_view path, uint64_t size)
: path_{ path }
, length_{ length }
, size_{ size }
{
}
private:
std::string path_;
uint64_t length_ = 0;
uint64_t size_ = 0;
};
tr_block_info block_info_ = tr_block_info{ 0, 0 };

View File

@ -1109,18 +1109,18 @@ tr_file_view tr_torrentFile(tr_torrent const* tor, tr_file_index_t i)
{
TR_ASSERT(tr_isTorrent(tor));
auto const* subpath = tor->fileSubpath(i);
auto const& subpath = tor->fileSubpath(i);
auto const priority = tor->file_priorities_.filePriority(i);
auto const wanted = tor->files_wanted_.fileWanted(i);
auto const length = tor->fileSize(i);
if (tor->completeness == TR_SEED || length == 0)
{
return { subpath, length, length, 1.0, priority, wanted };
return { subpath.c_str(), length, length, 1.0, priority, wanted };
}
auto const have = tor->completion.countHasBytesInSpan(tor->fpm_.byteSpan(i));
return { subpath, have, length, have >= length ? 1.0 : have / double(length), priority, wanted };
return { subpath.c_str(), have, length, have >= length ? 1.0 : have / double(length), priority, wanted };
}
size_t tr_torrentFileCount(tr_torrent const* torrent)
@ -2513,7 +2513,7 @@ static void tr_torrentFileCompleted(tr_torrent* tor, tr_file_index_t i)
char* sub = nullptr;
if (tr_torrentFindFile2(tor, i, &base, &sub, nullptr))
{
if (char const* file_subpath = tor->fileSubpath(i); strcmp(sub, file_subpath) != 0)
if (auto const& file_subpath = tor->fileSubpath(i); file_subpath != sub)
{
auto const oldpath = tr_strvPath(base, sub);
auto const newpath = tr_strvPath(base, file_subpath);
@ -2858,26 +2858,21 @@ static bool renameArgsAreValid(char const* oldpath, char const* newname)
strchr(newname, TR_PATH_DELIMITER) == nullptr;
}
static tr_file_index_t* renameFindAffectedFiles(tr_torrent* tor, char const* oldpath, size_t* setme_n)
static auto renameFindAffectedFiles(tr_torrent* tor, std::string_view oldpath)
{
auto indices = std::vector<tr_file_index_t>{};
auto oldpath_as_dir = tr_strvJoin(oldpath, "/"sv);
auto const n_files = tor->fileCount();
auto n_affected_files = size_t{};
auto* const indices = tr_new0(tr_file_index_t, n_files);
auto const oldpath_len = strlen(oldpath);
for (tr_file_index_t i = 0; i < n_files; ++i)
{
char const* name = tor->fileSubpath(i);
size_t const len = strlen(name);
if ((len == oldpath_len || (len > oldpath_len && name[oldpath_len] == '/')) && memcmp(oldpath, name, oldpath_len) == 0)
auto const& name = tor->fileSubpath(i);
if (name == oldpath || tr_strvStartsWith(name, oldpath_as_dir))
{
indices[n_affected_files++] = i;
indices.push_back(i);
}
}
*setme_n = n_affected_files;
return indices;
}
@ -2999,10 +2994,8 @@ static void torrentRenamePath(void* vdata)
}
else
{
auto n = size_t{};
tr_file_index_t* const file_indices = renameFindAffectedFiles(tor, oldpath, &n);
if (n == 0)
auto const file_indices = renameFindAffectedFiles(tor, oldpath);
if (std::empty(file_indices))
{
error = EINVAL;
}
@ -3013,13 +3006,13 @@ static void torrentRenamePath(void* vdata)
if (error == 0)
{
/* update tr_info.files */
for (size_t i = 0; i < n; ++i)
for (auto const& file_index : file_indices)
{
renameTorrentFileString(tor, oldpath, newname, file_indices[i]);
renameTorrentFileString(tor, oldpath, newname, file_index);
}
/* update tr_info.name if user changed the toplevel */
if (n == tor->fileCount() && strchr(oldpath, '/') == nullptr)
if (std::size(file_indices) == tor->fileCount() && strchr(oldpath, '/') == nullptr)
{
tor->setName(newname);
}
@ -3028,8 +3021,6 @@ static void torrentRenamePath(void* vdata)
tor->setDirty();
}
}
tr_free(file_indices);
}
/***
@ -3134,10 +3125,5 @@ void tr_torrent::setName(std::string_view name)
void tr_torrent::setFileSubpath(tr_file_index_t i, std::string_view subpath)
{
if (fileSubpath(i) != subpath)
{
auto* old = this->info.files[i].name;
this->info.files[i].name = tr_strvDup(subpath);
tr_free(old);
}
this->info.files[i].subpath = subpath;
}

View File

@ -372,21 +372,17 @@ public:
[[nodiscard]] tr_file_index_t fileCount() const
{
return info.fileCount;
return std::size(info.files);
}
[[nodiscard]] char const* fileSubpath(tr_file_index_t i) const
[[nodiscard]] std::string const& fileSubpath(tr_file_index_t i) const
{
TR_ASSERT(i < this->fileCount());
return info.files[i].name ? info.files[i].name : "";
return info.fileSubpath(i);
}
[[nodiscard]] auto fileSize(tr_file_index_t i) const
{
TR_ASSERT(i < this->fileCount());
return info.files[i].length;
return info.fileSize(i);
}
void setFileSubpath(tr_file_index_t i, std::string_view subpath);

View File

@ -1502,8 +1502,8 @@ void tr_torrentVerify(tr_torrent* torrent, tr_verify_done_func callback_func_or_
struct tr_file
{
// public
char* name; /* Path to the file */
uint64_t length; /* Length of the file, in bytes */
std::string subpath; /* Path to the file */
uint64_t size; /* Length of the file, in bytes */
};
/** @brief information about a torrent that comes from its metainfo file */
@ -1528,7 +1528,22 @@ struct tr_info
// Private.
// Use tr_torrentFile() and tr_torrentFileCount() instead.
tr_file* files;
std::vector<tr_file> files;
tr_file_index_t fileCount() const
{
return std::size(files);
}
std::string const& fileSubpath(tr_file_index_t i) const
{
return files[i].subpath;
}
auto fileSize(tr_file_index_t i) const
{
return files[i].size;
}
// TODO(ckerr) aggregate this directly, rather than using a shared_ptr, when tr_info is private
std::shared_ptr<tr_announce_list> announce_list;
@ -1537,7 +1552,6 @@ struct tr_info
time_t dateCreated;
unsigned int webseedCount;
tr_file_index_t fileCount;
uint32_t pieceSize;
tr_piece_index_t pieceCount;

View File

@ -1102,7 +1102,7 @@ static void removeKeRangerRansomware()
}
//determine to show the options window
auto const is_multifile = std::size(metainfo.files()) > 1;
auto const is_multifile = metainfo.fileCount() > 1;
BOOL const showWindow = type == ADD_SHOW_OPTIONS ||
([fDefaults boolForKey:@"DownloadAsk"] && (is_multifile || ![fDefaults boolForKey:@"DownloadAskMulti"]) &&
(type != ADD_AUTO || ![fDefaults boolForKey:@"DownloadAskManual"]));

View File

@ -100,7 +100,7 @@
size += metainfo.totalSize();
auto const n_files = std::size(metainfo.files());
auto const n_files = metainfo.fileCount();
fileCount += n_files;
if (n_files == 1)
{

View File

@ -69,7 +69,7 @@ OSStatus GeneratePreviewForURL(void* thisInterface, QLPreviewRequestRef preview,
NSString* name = [NSString stringWithUTF8String:metainfo.name().c_str()];
auto const n_files = std::size(metainfo.files());
auto const n_files = metainfo.fileCount();
auto const is_multifile = n_files > 1;
NSString* fileTypeString = is_multifile ? NSFileTypeForHFSTypeCode(kGenericFolderIcon) : [name pathExtension];
@ -190,9 +190,9 @@ OSStatus GeneratePreviewForURL(void* thisInterface, QLPreviewRequestRef preview,
#warning display size?
#warning display folders?
for (auto const& file : metainfo.files())
for (tr_file_index_t i = 0; i < n_files; ++i)
{
NSString* fullFilePath = [NSString stringWithUTF8String:file.path().c_str()];
NSString* fullFilePath = [NSString stringWithUTF8String:metainfo.fileSubpath(i).c_str()];
NSCAssert([fullFilePath hasPrefix:[name stringByAppendingString:@"/"]], @"Expected file path %@ to begin with %@/", fullFilePath, name);
NSString* shortenedFilePath = [fullFilePath substringFromIndex:[name length] + 1];

View File

@ -172,30 +172,27 @@ void OptionsDialog::reload()
metainfo_ = metainfo;
}
bool const have_files_to_show = metainfo_ && !std::empty(metainfo_->files());
bool const have_files_to_show = metainfo_ && !std::empty(*metainfo_);
ui_.filesView->setVisible(have_files_to_show);
layout()->setSizeConstraint(have_files_to_show ? QLayout::SetDefaultConstraint : QLayout::SetFixedSize);
if (metainfo_)
{
int i = 0;
auto const n_files = std::size(metainfo_->files());
auto const n_files = metainfo_->fileCount();
priorities_.assign(n_files, TR_PRI_NORMAL);
wanted_.assign(n_files, true);
for (auto const& file : metainfo_->files())
for (tr_file_index_t i = 0; i < n_files; ++i)
{
auto f = TorrentFile{};
f.index = i;
f.priority = priorities_[i];
f.wanted = wanted_[i];
f.size = file.length();
f.size = metainfo_->fileSize(i);
f.have = 0;
f.filename = QString::fromStdString(file.path());
f.filename = QString::fromStdString(metainfo_->fileSubpath(i));
files_.push_back(f);
++i;
}
}

View File

@ -388,7 +388,7 @@ TEST_F(AnnounceListTest, save)
// test that non-announce parts of the metainfo are the same
EXPECT_STREQ(original->info.name, saved->info.name);
EXPECT_EQ(original->info.fileCount, saved->info.fileCount);
EXPECT_EQ(original->info.fileCount(), saved->info.fileCount());
EXPECT_EQ(original->info.dateCreated, saved->info.dateCreated);
EXPECT_EQ(original->pieces, saved->pieces);

View File

@ -79,7 +79,7 @@ protected:
EXPECT_EQ(payloadSize, metainfo.totalSize());
EXPECT_EQ(makeString(tr_sys_path_basename(input_file.data(), nullptr)), metainfo.name());
EXPECT_EQ(comment, metainfo.comment());
EXPECT_EQ(tr_file_index_t{ 1 }, std::size(metainfo.files()));
EXPECT_EQ(tr_file_index_t{ 1 }, metainfo.fileCount());
EXPECT_EQ(isPrivate, metainfo.isPrivate());
EXPECT_EQ(size_t(trackerCount), std::size(metainfo.announceList()));
@ -160,7 +160,7 @@ protected:
tr_free(tmpstr);
EXPECT_EQ(comment, metainfo.comment());
EXPECT_EQ(source, metainfo.source());
EXPECT_EQ(payload_count, std::size(metainfo.files()));
EXPECT_EQ(payload_count, metainfo.fileCount());
EXPECT_EQ(is_private, metainfo.isPrivate());
EXPECT_EQ(size_t(tracker_count), std::size(metainfo.announceList()));

View File

@ -22,6 +22,8 @@
#include <cstring> // strcmp()
#include <string>
using namespace std::literals;
namespace libtransmission
{
@ -262,7 +264,7 @@ TEST_F(RenameTest, multifileTorrent)
"MjpwaWVjZSBsZW5ndGhpMzI3NjhlNjpwaWVjZXMyMDp27buFkmy8ICfNX4nsJmt0Ckm2Ljc6cHJp"
"dmF0ZWkwZWVl");
EXPECT_TRUE(tr_isTorrent(tor));
auto* files = tor->info.files;
auto& files = tor->info.files;
// sanity check the info
EXPECT_STREQ("Felidae", tr_torrentName(tor));
@ -318,8 +320,7 @@ TEST_F(RenameTest, multifileTorrent)
// (while the branch is renamed: confirm that the .resume file remembers the changes)
tr_torrentSaveResume(tor);
// this is a bit dodgy code-wise, but let's make sure the .resume file got the name
tr_free(files[1].name);
files[1].name = tr_strdup("gabba gabba hey");
files[1].subpath = "gabba gabba hey";
auto const loaded = tr_torrentLoadResume(tor, ~0ULL, ctor, nullptr);
EXPECT_NE(decltype(loaded){ 0 }, (loaded & TR_FR_FILENAMES));
EXPECT_EQ(expected_files[0], tr_torrentFile(tor, 0).name);
@ -461,13 +462,12 @@ TEST_F(RenameTest, partialFile)
***/
auto* tor = zeroTorrentInit();
auto const& files = tor->info.files;
EXPECT_EQ(TotalSize, tor->totalSize());
EXPECT_EQ(PieceSize, tor->pieceSize());
EXPECT_EQ(PieceCount, tor->pieceCount());
EXPECT_STREQ("files-filled-with-zeroes/1048576", files[0].name);
EXPECT_STREQ("files-filled-with-zeroes/4096", files[1].name);
EXPECT_STREQ("files-filled-with-zeroes/512", files[2].name);
EXPECT_EQ("files-filled-with-zeroes/1048576"sv, tor->fileSubpath(0));
EXPECT_EQ("files-filled-with-zeroes/4096"sv, tor->fileSubpath(1));
EXPECT_EQ("files-filled-with-zeroes/512"sv, tor->fileSubpath(2));
zeroTorrentPopulate(tor, false);
EXPECT_EQ(Length[0], tr_torrentFile(tor, 0).have + PieceSize);
@ -483,14 +483,14 @@ TEST_F(RenameTest, partialFile)
EXPECT_EQ(0, torrentRenameAndWait(tor, "files-filled-with-zeroes", "foo"));
EXPECT_EQ(0, torrentRenameAndWait(tor, "foo/1048576", "bar"));
auto strings = std::array<char const*, 3>{};
strings[0] = "foo/bar";
strings[1] = "foo/4096";
strings[2] = "foo/512";
auto strings = std::array<std::string_view, 3>{};
strings[0] = "foo/bar"sv;
strings[1] = "foo/4096"sv;
strings[2] = "foo/512"sv;
for (tr_file_index_t i = 0; i < 3; ++i)
{
EXPECT_STREQ(strings[i], files[i].name);
EXPECT_EQ(strings[i], tor->fileSubpath(i));
}
strings[0] = "foo/bar.part";

View File

@ -43,7 +43,7 @@ TEST_F(TorrentMetainfoTest, magnetLink)
auto metainfo = tr_torrent_metainfo{};
EXPECT_TRUE(metainfo.parseMagnet(MagnetLink));
EXPECT_EQ(0, std::size(metainfo.files())); // because it's a magnet link
EXPECT_EQ(0, metainfo.fileCount()); // because it's a magnet link
EXPECT_EQ(2, std::size(metainfo.announceList()));
EXPECT_EQ(MagnetLink, metainfo.magnet());
}

View File

@ -177,11 +177,11 @@ void showInfo(app_opts const& opts, tr_torrent_metainfo const& metainfo)
printf("\nFILES\n\n");
auto filenames = std::vector<std::string>{};
for (auto const& file : metainfo.files())
for (tr_file_index_t i = 0, n = metainfo.fileCount(); i < n; ++i)
{
std::string filename = file.path();
std::string filename = metainfo.fileSubpath(i);
filename += " (";
filename += tr_formatter_size_B(file.length());
filename += tr_formatter_size_B(metainfo.fileSize(i));
filename += ')';
filenames.emplace_back(filename);
}