blob: 4302b539d69a3cf3b5102102f256b79f32758656 [file] [log] [blame]
spirosmastorakisa6057f52016-01-28 13:34:41 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3* Copyright (c) 2016 Regents of the University of California.
4*
5* This file is part of the nTorrent codebase.
6*
7* nTorrent is free software: you can redistribute it and/or modify it under the
8* terms of the GNU Lesser General Public License as published by the Free Software
9* Foundation, either version 3 of the License, or (at your option) any later version.
10*
11* nTorrent is distributed in the hope that it will be useful, but WITHOUT ANY
12* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14*
15* You should have received copies of the GNU General Public License and GNU Lesser
16* General Public License along with nTorrent, e.g., in COPYING.md file. If not, see
17* <http://www.gnu.org/licenses/>.
18*
19* See AUTHORS for complete list of nTorrent authors and contributors.
20*/
21
22#include "torrent-file.hpp"
23
24#include <algorithm>
25
26#include <boost/range/adaptors.hpp>
27
28namespace ndn {
29
30namespace ntorrent {
31
32BOOST_CONCEPT_ASSERT((WireEncodable<TorrentFile>));
33BOOST_CONCEPT_ASSERT((WireDecodable<TorrentFile>));
34static_assert(std::is_base_of<Data::Error, TorrentFile::Error>::value,
35 "TorrentFile::Error should inherit from Data::Error");
36
37TorrentFile::TorrentFile(const Name& torrentFileName,
38 const Name& torrentFilePtr,
39 const Name& commonPrefix,
40 const std::vector<ndn::Name>& catalog)
41 : Data(torrentFileName)
42 , m_commonPrefix(commonPrefix)
43 , m_torrentFilePtr(torrentFilePtr)
44 , m_catalog(catalog)
45{
46}
47
48TorrentFile::TorrentFile(const Name& torrentFileName,
49 const Name& commonPrefix,
50 const std::vector<ndn::Name>& catalog)
51 : Data(torrentFileName)
52 , m_commonPrefix(commonPrefix)
53 , m_catalog(catalog)
54{
55}
56
57TorrentFile::TorrentFile(const Block& block)
58{
59 this->wireDecode(block);
60}
61
62const Name&
63TorrentFile::getName() const
64{
65 return Data::getName();
66}
67
68const Name&
69TorrentFile::getCommonPrefix() const
70{
71 return m_commonPrefix;
72}
73
74void
75TorrentFile::createSuffixCatalog()
76{
77 for (auto i = m_catalog.begin() ; i != m_catalog.end(); ++i) {
78 m_suffixCatalog.push_back((*i).getSubName(m_commonPrefix.size()));
79 }
80}
81
82shared_ptr<Name>
83TorrentFile::getTorrentFilePtr() const
84{
85 if (this->hasTorrentFilePtr()) {
86 return make_shared<Name>(m_torrentFilePtr);
87 }
88 return nullptr;
89}
90
91void
92TorrentFile::constructLongNames()
93{
94 for (auto i = m_suffixCatalog.begin(); i != m_suffixCatalog.end(); ++i) {
95 Name commonPrefix = m_commonPrefix;
96 m_catalog.push_back(commonPrefix.append((*i)));
97 }
98}
99
100template<encoding::Tag TAG>
101size_t
102TorrentFile::encodeContent(EncodingImpl<TAG>& encoder) const
103{
104 // TorrentFileContent ::= CONTENT-TYPE TLV-LENGTH
105 // Suffix+
106 // CommonPrefix
107 // TorrentFilePtr?
108
109 // Suffix ::= NAME-TYPE TLV-LENGTH
110 // Name
111
112 // CommonPrefix ::= NAME-TYPE TLV-LENGTH
113 // Name
114
115 // TorrentFilePtr ::= NAME-TYPE TLV-LENGTH
116 // Name
117
118 size_t totalLength = 0;
119 for (const auto& name : m_suffixCatalog | boost::adaptors::reversed) {
120 size_t fileManifestSuffixLength = 0;
121 fileManifestSuffixLength += name.wireEncode(encoder);
122 totalLength += fileManifestSuffixLength;
123 }
124 totalLength += m_commonPrefix.wireEncode(encoder);
125 if (!m_torrentFilePtr.empty()) {
126 size_t torrentFilePtrLength = 0;
127 torrentFilePtrLength += m_torrentFilePtr.wireEncode(encoder);
128 totalLength += torrentFilePtrLength;
129 }
130
131 totalLength += encoder.prependVarNumber(totalLength);
132 totalLength += encoder.prependVarNumber(tlv::Content);
133 return totalLength;
134}
135
136bool
137TorrentFile::erase(const Name& name)
138{
139 auto found = std::find(m_catalog.begin(), m_catalog.end(), name);
140 if (found != m_catalog.end()) {
141 m_catalog.erase(found);
142 return true;
143 }
144 return false;
145}
146
147void
148TorrentFile::encodeContent()
149{
150 onChanged();
151
152 EncodingEstimator estimator;
153 size_t estimatedSize = encodeContent(estimator);
154
155 EncodingBuffer buffer(estimatedSize, 0);
156 encodeContent(buffer);
157
158 setContentType(tlv::ContentType_Blob);
159 setContent(buffer.block());
160}
161
162void
163TorrentFile::decodeContent()
164{
165 // TorrentFileContent ::= CONTENT-TYPE TLV-LENGTH
166 // Suffix+
167 // CommonPrefix
168 // TorrentFilePtr?
169
170 // Suffix ::= NAME-TYPE TLV-LENGTH
171 // Name
172
173 // CommonPrefix ::= NAME-TYPE TLV-LENGTH
174 // Name
175
176 // TorrentFilePtr ::= NAME-TYPE TLV-LENGTH
177 // Name
178
179 if (getContentType() != tlv::ContentType_Blob) {
180 BOOST_THROW_EXCEPTION(Error("Expected Content Type Blob"));
181 }
182
183 const Block& content = Data::getContent();
184 content.parse();
185
186 // Check whether there is a TorrentFilePtr
187 auto element = content.elements_begin();
188 if (content.elements_end() == element) {
189 BOOST_THROW_EXCEPTION(Error(".Torrent-file with empty content"));
190 }
191 element->parse();
192 Name name(*element);
193 if (name.empty())
194 BOOST_THROW_EXCEPTION(Error("Empty name included in the .torrent-file"));
195
196 if (name.get(name.size() - 3) == name::Component(".torrent-file")) {
197 m_torrentFilePtr = name;
198 ++element;
199 m_commonPrefix = Name(*element);
200 if (m_commonPrefix.empty()) {
201 BOOST_THROW_EXCEPTION(Error("Common prefix cannot be empty"));
202 }
203 }
204 else {
205 m_commonPrefix = name;
206 }
207 element++;
208 for (; element != content.elements_end(); ++element) {
209 element->parse();
210 Name fileManifestSuffix(*element);
211 if (fileManifestSuffix.empty())
212 BOOST_THROW_EXCEPTION(Error("Empty manifest file name included in the .torrent-file"));
213 this->insertToSuffixCatalog(fileManifestSuffix);
214 }
215 if (m_suffixCatalog.size() == 0) {
216 BOOST_THROW_EXCEPTION(Error(".Torrent-file with empty catalog of file manifest names"));
217 }
218}
219
220void
221TorrentFile::wireDecode(const Block& wire)
222{
223 m_catalog.clear();
224 m_suffixCatalog.clear();
225 Data::wireDecode(wire);
226 this->decodeContent();
227 this->constructLongNames();
228}
229
230const Block&
231TorrentFile::wireEncode()
232{
233 this->createSuffixCatalog();
234 this->encodeContent();
235 m_suffixCatalog.clear();
236 return Data::wireEncode();
237}
238
239} // namespace ntorrent
240
241} // namespace ndn