3
Copyright (c) 2008, Arvid Norberg
6
Redistribution and use in source and binary forms, with or without
7
modification, are permitted provided that the following conditions
10
* Redistributions of source code must retain the above copyright
11
notice, this list of conditions and the following disclaimer.
12
* Redistributions in binary form must reproduce the above copyright
13
notice, this list of conditions and the following disclaimer in
14
the documentation and/or other materials provided with the distribution.
15
* Neither the name of the author nor the names of its
16
contributors may be used to endorse or promote products derived
17
from this software without specific prior written permission.
19
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
POSSIBILITY OF SUCH DAMAGE.
33
#include "libtorrent/create_torrent.hpp"
34
#include "libtorrent/file_pool.hpp"
35
#include "libtorrent/storage.hpp"
37
#include <boost/date_time/posix_time/posix_time.hpp>
38
#include <boost/date_time/gregorian/gregorian.hpp>
39
#include <boost/bind.hpp>
41
namespace gr = boost::gregorian;
45
create_torrent::create_torrent(file_storage& fs, int size)
47
, m_creation_date(pt::second_clock::universal_time())
48
, m_multifile(fs.num_files() > 1)
51
TORRENT_ASSERT(fs.num_files() > 0);
52
#if BOOST_VERSION < 103600
53
if (!m_multifile && m_files.at(0).path.has_branch_path()) m_multifile = true;
55
if (!m_multifile && m_files.at(0).path.has_parent_path()) m_multifile = true;
58
// make sure the size is an even power of 2
60
for (int i = 0; i < 32; ++i)
64
TORRENT_ASSERT((size & ~(1 << i)) == 0);
69
m_files.set_piece_length(size);
70
m_files.set_num_pieces(static_cast<int>(
71
(m_files.total_size() + m_files.piece_length() - 1) / m_files.piece_length()));
72
m_piece_hash.resize(m_files.num_pieces());
75
create_torrent::create_torrent(file_storage& fs)
77
, m_creation_date(pt::second_clock::universal_time())
78
, m_multifile(fs.num_files() > 1)
81
TORRENT_ASSERT(fs.num_files() > 0);
82
#if BOOST_VERSION < 103600
83
if (!m_multifile && m_files.at(0).path.has_branch_path()) m_multifile = true;
85
if (!m_multifile && m_files.at(0).path.has_parent_path()) m_multifile = true;
88
const int target_size = 40 * 1024;
89
int size = fs.total_size() / (target_size / 20);
91
for (int i = 4*1024*1024; i > 16*1024; i /= 2)
93
if (size < i) continue;
98
m_files.set_piece_length(size);
99
m_files.set_num_pieces(static_cast<int>(
100
(m_files.total_size() + m_files.piece_length() - 1) / m_files.piece_length()));
101
m_piece_hash.resize(m_files.num_pieces());
103
entry create_torrent::generate() const
105
TORRENT_ASSERT(m_files.piece_length() > 0);
107
if (m_files.num_files() == 0)
109
// TODO: throw something here
116
if (!m_urls.empty()) dict["announce"] = m_urls.front().first;
118
if (!m_nodes.empty())
120
entry& nodes = dict["nodes"];
121
entry::list_type& nodes_list = nodes.list();
122
for (nodes_t::const_iterator i = m_nodes.begin()
123
, end(m_nodes.end()); i != end; ++i)
125
entry::list_type node;
126
node.push_back(entry(i->first));
127
node.push_back(entry(i->second));
128
nodes_list.push_back(entry(node));
132
if (m_urls.size() > 1)
134
entry trackers(entry::list_t);
135
entry tier(entry::list_t);
136
int current_tier = m_urls.front().second;
137
for (std::vector<announce_entry>::const_iterator i = m_urls.begin();
138
i != m_urls.end(); ++i)
140
if (i->second != current_tier)
142
current_tier = i->second;
143
trackers.list().push_back(tier);
146
tier.list().push_back(entry(i->first));
148
trackers.list().push_back(tier);
149
dict["announce-list"] = trackers;
152
if (!m_comment.empty())
153
dict["comment"] = m_comment;
155
dict["creation date"] =
156
(m_creation_date - pt::ptime(gr::date(1970, gr::Jan, 1))).total_seconds();
158
if (!m_created_by.empty())
159
dict["created by"] = m_created_by;
161
if (!m_url_seeds.empty())
163
if (m_url_seeds.size() == 1)
165
dict["url-list"] = m_url_seeds.front();
169
entry& list = dict["url-list"];
170
for (std::vector<std::string>::const_iterator i
171
= m_url_seeds.begin(); i != m_url_seeds.end(); ++i)
173
list.list().push_back(entry(*i));
178
entry& info = dict["info"];
179
info["name"] = m_files.name();
181
if (m_private) info["private"] = 1;
185
info["length"] = m_files.at(0).size;
189
if (!info.find_key("files"))
191
entry& files = info["files"];
193
for (file_storage::iterator i = m_files.begin();
194
i != m_files.end(); ++i)
196
files.list().push_back(entry());
197
entry& file_e = files.list().back();
198
file_e["length"] = i->size;
199
entry& path_e = file_e["path"];
201
#if BOOST_VERSION < 103600
202
TORRENT_ASSERT(i->path.has_branch_path());
204
TORRENT_ASSERT(i->path.has_parent_path());
206
TORRENT_ASSERT(*i->path.begin() == m_files.name());
208
for (fs::path::iterator j = boost::next(i->path.begin());
209
j != i->path.end(); ++j)
211
path_e.list().push_back(entry(*j));
217
info["piece length"] = m_files.piece_length();
218
entry& pieces = info["pieces"];
220
std::string& p = pieces.string();
222
for (std::vector<sha1_hash>::const_iterator i = m_piece_hash.begin();
223
i != m_piece_hash.end(); ++i)
225
p.append((char*)i->begin(), (char*)i->end());
228
std::vector<char> buf;
229
bencode(std::back_inserter(buf), info);
230
m_info_hash = hasher(&buf[0], buf.size()).final();
236
void create_torrent::add_tracker(std::string const& url, int tier)
238
m_urls.push_back(announce_entry(url, tier));
241
std::sort(m_urls.begin(), m_urls.end()
242
, bind(&announce_entry::second, _1) < bind(&announce_entry::second, _2));
245
void create_torrent::set_hash(int index, sha1_hash const& h)
247
TORRENT_ASSERT(index >= 0);
248
TORRENT_ASSERT(index < (int)m_piece_hash.size());
249
m_piece_hash[index] = h;
252
void create_torrent::add_node(std::pair<std::string, int> const& node)
254
m_nodes.push_back(node);
257
void create_torrent::add_url_seed(std::string const& url)
259
m_url_seeds.push_back(url);
262
void create_torrent::set_comment(char const* str)
267
void create_torrent::set_creator(char const* str)