2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * In addition, as a special exception, the copyright holders give permission to
20 * link this program with the OpenSSL project's "OpenSSL" library (or with
21 * modified versions of it that use the same license as the "OpenSSL" library),
22 * and distribute the linked executables. You must obey the GNU General Public
23 * License in all respects for all of the code used other than "OpenSSL". If you
24 * modify file(s), you may extend this exception to your version of the file(s),
25 * but you are not obligated to do so. If you do not wish to do so, delete this
26 * exception statement from your version.
29 #include "torrentinfo.h"
31 #include <libtorrent/version.hpp>
38 #include "base/global.h"
39 #include "base/path.h"
41 #include "trackerentry.h"
43 using namespace BitTorrent
;
45 const int TORRENTINFO_TYPEID
= qRegisterMetaType
<TorrentInfo
>();
47 TorrentInfo::TorrentInfo(const lt::torrent_info
&nativeInfo
)
48 : m_nativeInfo
{std::make_shared
<const lt::torrent_info
>(nativeInfo
)}
50 Q_ASSERT(m_nativeInfo
->is_valid() && (m_nativeInfo
->num_files() > 0));
52 const lt::file_storage
&fileStorage
= m_nativeInfo
->orig_files();
53 m_nativeIndexes
.reserve(fileStorage
.num_files());
54 for (const lt::file_index_t nativeIndex
: fileStorage
.file_range())
56 if (!fileStorage
.pad_file_at(nativeIndex
))
57 m_nativeIndexes
.append(nativeIndex
);
61 TorrentInfo
&TorrentInfo::operator=(const TorrentInfo
&other
)
65 m_nativeInfo
= other
.m_nativeInfo
;
66 m_nativeIndexes
= other
.m_nativeIndexes
;
71 bool TorrentInfo::isValid() const
73 return (m_nativeInfo
!= nullptr);
76 InfoHash
TorrentInfo::infoHash() const
78 if (!isValid()) return {};
80 #ifdef QBT_USES_LIBTORRENT2
81 return m_nativeInfo
->info_hashes();
83 return m_nativeInfo
->info_hash();
87 QString
TorrentInfo::name() const
89 if (!isValid()) return {};
91 return QString::fromStdString(m_nativeInfo
->orig_files().name());
94 bool TorrentInfo::isPrivate() const
96 if (!isValid()) return false;
98 return m_nativeInfo
->priv();
101 qlonglong
TorrentInfo::totalSize() const
103 if (!isValid()) return -1;
105 return m_nativeInfo
->total_size();
108 int TorrentInfo::filesCount() const
110 if (!isValid()) return -1;
112 return m_nativeIndexes
.size();
115 int TorrentInfo::pieceLength() const
117 if (!isValid()) return -1;
119 return m_nativeInfo
->piece_length();
122 int TorrentInfo::pieceLength(const int index
) const
124 if (!isValid()) return -1;
126 return m_nativeInfo
->piece_size(lt::piece_index_t
{index
});
129 int TorrentInfo::piecesCount() const
131 if (!isValid()) return -1;
133 return m_nativeInfo
->num_pieces();
136 Path
TorrentInfo::filePath(const int index
) const
138 if (!isValid()) return {};
140 Q_ASSERT(index
>= 0);
141 Q_ASSERT(index
< m_nativeIndexes
.size());
142 if ((index
< 0) || (index
>= m_nativeIndexes
.size()))
145 return Path(m_nativeInfo
->orig_files().file_path(m_nativeIndexes
[index
]));
148 PathList
TorrentInfo::filePaths() const
151 list
.reserve(filesCount());
152 for (int i
= 0; i
< filesCount(); ++i
)
158 qlonglong
TorrentInfo::fileSize(const int index
) const
160 if (!isValid()) return -1;
162 Q_ASSERT(index
>= 0);
163 Q_ASSERT(index
< m_nativeIndexes
.size());
164 if ((index
< 0) || (index
>= m_nativeIndexes
.size()))
167 return m_nativeInfo
->orig_files().file_size(m_nativeIndexes
[index
]);
170 qlonglong
TorrentInfo::fileOffset(const int index
) const
172 if (!isValid()) return -1;
174 Q_ASSERT(index
>= 0);
175 Q_ASSERT(index
< m_nativeIndexes
.size());
176 if ((index
< 0) || (index
>= m_nativeIndexes
.size()))
179 return m_nativeInfo
->orig_files().file_offset(m_nativeIndexes
[index
]);
182 QByteArray
TorrentInfo::rawData() const
184 if (!isValid()) return {};
185 #ifdef QBT_USES_LIBTORRENT2
186 const lt::span
<const char> infoSection
{m_nativeInfo
->info_section()};
187 return {infoSection
.data(), static_cast<int>(infoSection
.size())};
189 return {m_nativeInfo
->metadata().get(), m_nativeInfo
->metadata_size()};
193 PathList
TorrentInfo::filesForPiece(const int pieceIndex
) const
195 // no checks here because fileIndicesForPiece() will return an empty list
196 const QList
<int> fileIndices
= fileIndicesForPiece(pieceIndex
);
199 res
.reserve(fileIndices
.size());
200 std::transform(fileIndices
.begin(), fileIndices
.end(), std::back_inserter(res
)
201 , [this](int i
) { return filePath(i
); });
206 QList
<int> TorrentInfo::fileIndicesForPiece(const int pieceIndex
) const
208 if (!isValid() || (pieceIndex
< 0) || (pieceIndex
>= piecesCount()))
211 const std::vector
<lt::file_slice
> files
= m_nativeInfo
->map_block(
212 lt::piece_index_t
{pieceIndex
}, 0, m_nativeInfo
->piece_size(lt::piece_index_t
{pieceIndex
}));
214 res
.reserve(static_cast<decltype(res
)::size_type
>(files
.size()));
215 for (const lt::file_slice
&fileSlice
: files
)
217 const int index
= m_nativeIndexes
.indexOf(fileSlice
.file_index
);
225 QList
<QByteArray
> TorrentInfo::pieceHashes() const
230 const int count
= piecesCount();
231 QList
<QByteArray
> hashes
;
232 hashes
.reserve(count
);
234 for (int i
= 0; i
< count
; ++i
)
235 hashes
+= {m_nativeInfo
->hash_for_piece_ptr(lt::piece_index_t
{i
}), SHA1Hash::length()};
240 TorrentInfo::PieceRange
TorrentInfo::filePieces(const Path
&filePath
) const
242 return filePieces(fileIndex(filePath
));
245 TorrentInfo::PieceRange
TorrentInfo::filePieces(const int fileIndex
) const
250 if ((fileIndex
< 0) || (fileIndex
>= filesCount()))
253 const lt::file_storage
&files
= m_nativeInfo
->orig_files();
254 const auto fileSize
= files
.file_size(m_nativeIndexes
[fileIndex
]);
255 const auto fileOffset
= files
.file_offset(m_nativeIndexes
[fileIndex
]);
257 const int beginIdx
= (fileOffset
/ pieceLength());
258 const int endIdx
= ((fileOffset
+ fileSize
- 1) / pieceLength());
261 return {beginIdx
, 0};
262 return makeInterval(beginIdx
, endIdx
);
265 bool TorrentInfo::matchesInfoHash(const InfoHash
&otherInfoHash
) const
270 const InfoHash thisInfoHash
= infoHash();
272 if (thisInfoHash
.v1().isValid() && otherInfoHash
.v1().isValid()
273 && (thisInfoHash
.v1() != otherInfoHash
.v1()))
278 if (thisInfoHash
.v2().isValid() && otherInfoHash
.v2().isValid()
279 && (thisInfoHash
.v2() != otherInfoHash
.v2()))
284 if (!thisInfoHash
.v1().isValid() && otherInfoHash
.v1().isValid())
287 if (!thisInfoHash
.v2().isValid() && otherInfoHash
.v2().isValid())
293 int TorrentInfo::fileIndex(const Path
&filePath
) const
295 // the check whether the object is valid is not needed here
296 // because if filesCount() returns -1 the loop exits immediately
297 for (int i
= 0; i
< filesCount(); ++i
)
299 if (filePath
== this->filePath(i
))
306 std::shared_ptr
<lt::torrent_info
> TorrentInfo::nativeInfo() const
311 return std::make_shared
<lt::torrent_info
>(*m_nativeInfo
);
314 QList
<lt::file_index_t
> TorrentInfo::nativeIndexes() const
316 return m_nativeIndexes
;