blob: fe4fec8a0e19142895eb9ec53b5c22977e699ab6 [file] [log] [blame]
Mickey Sweatt3b0bea62016-01-25 22:12:27 -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#include "file-manifest.hpp"
22
23#include <boost/assert.hpp>
24#include <boost/range/adaptors.hpp>
25#include <boost/throw_exception.hpp>
26
27using std::vector;
28
29namespace ndn {
30namespace ntorrent {
31
32BOOST_CONCEPT_ASSERT((boost::EqualityComparable<FileManifest>));
33BOOST_CONCEPT_ASSERT((WireEncodable<FileManifest>));
34BOOST_CONCEPT_ASSERT((WireDecodable<FileManifest>));
35static_assert(std::is_base_of<Data::Error, FileManifest::Error>::value,
36 "FileManifest::Error should inherit from Data::Error");
37
38void
39FileManifest::wireDecode(const Block& wire)
40{
41 Data::wireDecode(wire);
42 this->decodeContent();
43}
44
Mickey Sweatt3b0bea62016-01-25 22:12:27 -080045template<ndn::encoding::Tag TAG>
46size_t
47FileManifest::encodeContent(ndn::EncodingImpl<TAG>& encoder) const {
48 // FileManifestName ::= NAME-TYPE TLV-LENGTH
49 // Name
50
51 // ManifestContent ::= CONTENT-TYPE TLV-LENGTH
52 // DataPacketName*
53 // CatalogPrefix
54 // DataPacketSize
55 // FileManifestPtr?
56
57 // DataPacketName ::= NAME-TYPE TLV-LENGTH
58 // Name
59
60 // CatalogPrefix ::= NAME-TYPE TLV-LENGTH
61 // Name
62
63 // DataPacketSize ::= CONTENT-TYPE TLV-LENGTH
64 // nonNegativeInteger
65
66 // FileManifestPtr ::= NAME-TYPE TLV-LENGTH
67 // Name
68
69 size_t totalLength = 0;
70
71 vector<Name> suffixCatalog;
72 suffixCatalog.reserve(m_catalog.size());
73 for (auto name: m_catalog) {
74 if (!m_catalogPrefix.isPrefixOf(name)) {
75 BOOST_THROW_EXCEPTION(Error(name.toUri() + "does not have the prefix"
76 + m_catalogPrefix.toUri()));
77 }
78 name = name.getSubName(m_catalogPrefix.size());
79 if (name.empty()) {
80 BOOST_THROW_EXCEPTION(Error("Manifest cannot include empty string"));
81 }
82 suffixCatalog.push_back(name);
83 }
84
85 for (const auto& name : suffixCatalog | boost::adaptors::reversed) {
86 totalLength += name.wireEncode(encoder);
87 }
88
89 totalLength += m_catalogPrefix.wireEncode(encoder);
90
91 totalLength += prependNonNegativeIntegerBlock(encoder, tlv::Content, m_dataPacketSize);
92
93 if (nullptr != m_submanifestPtr) {
94 totalLength += m_submanifestPtr->wireEncode(encoder);
95 }
96
97 totalLength += encoder.prependVarNumber(totalLength);
98 totalLength += encoder.prependVarNumber(tlv::Content);
99 return totalLength;
100
101}
102
103// MANIPULATORS
104void
105FileManifest::push_back(const Name& name)
106{
107 BOOST_ASSERT(name != m_catalogPrefix);
108 BOOST_ASSERT(m_catalogPrefix.isPrefixOf(name));
109 m_catalog.push_back(name);
110}
111
112bool
113FileManifest::remove(const ndn::Name& name) {
114 auto it = std::find(m_catalog.begin(), m_catalog.end(), name);
115 if (m_catalog.end() == it) {
116 return false;
117 }
118 m_catalog.erase(it);
119 return true;
120}
121
Mickey Sweatta768b242016-02-29 20:08:05 -0800122void
123FileManifest::finalize() {
124 m_catalog.shrink_to_fit();
125 encodeContent();
126}
127
Mickey Sweatt3b0bea62016-01-25 22:12:27 -0800128void FileManifest::encodeContent() {
129 // Name
130 // <file_name>/ImplicitDigest
131 // Content
132 // MetaData
133 // DataPtr*
134 // ManifestPointer?
135 //
136 // DataPtr := HashValue
137 // ManifestPtr := HashValue
138 // HashValue := OCTET[32]
139
140 // MetaData := Property*
141 // Property := DataSize | Signature
142 onChanged();
143
144 EncodingEstimator estimator;
145 size_t estimatedSize = encodeContent(estimator);
146
147 EncodingBuffer buffer(estimatedSize, 0);
148 encodeContent(buffer);
149
150 setContentType(tlv::ContentType_Blob);
151 setContent(buffer.block());
152}
153
154void
155FileManifest::decodeContent() {
156 // ManifestContent ::= CONTENT-TYPE TLV-LENGTH
157 // DataPacketName*
158 // CatalogPrefix
159 // DataPacketSize
160 // FileManifestPtr?
161
162
163 // DataPacketName ::= NAME-TYPE TLV-LENGTH
164 // Name
165
166 // CatalogPrefix ::= NAME-TYPE TLV-LENGTH
167 // Name
168
169 // DataPacketSize ::= CONTENT-TYPE TLV-LENGTH
170 // nonNegativeInteger
171
172 // FileManifestPtr ::= NAME-TYPE TLV-LENGTH
173 // Name
174
175 if (getContentType() != tlv::ContentType_Blob) {
176 BOOST_THROW_EXCEPTION(Error("Expected Content Type Blob"));
177 }
178
179 const Block& content = Data::getContent();
180 content.parse();
181
182 auto element = content.elements_begin();
183
184 if (content.elements_end() == element) {
185 BOOST_THROW_EXCEPTION(Error("FileManifest with empty content"));
186 }
187
188 element->parse();
189 Name name(*element);
190
191 // Submanifest ptr
192 if (!name.empty()) {
193 m_submanifestPtr = std::make_shared<Name>(name);
194 ++element;
195 }
196
197 // DataPacketSize
198 m_dataPacketSize = readNonNegativeInteger(*element);
199 ++element;
200
201 // CatalogPrefix
202 m_catalogPrefix = Name(*element);
203 element++;
204
205 // Catalog
206 m_catalog.clear();
207 for (; element != content.elements_end(); ++element) {
208 element->parse();
209 name = m_catalogPrefix;
210 name.append(Name(*element));
211 if (name == m_catalogPrefix) {
212 BOOST_THROW_EXCEPTION(Error("Empty name included in a FileManifest"));
213 }
214 push_back(name);
215 }
216}
217
218bool operator==(const FileManifest& lhs, const FileManifest& rhs) {
219 return lhs.name() == rhs.name()
220 && lhs.data_packet_size() == rhs.data_packet_size()
221 && (lhs.submanifest_ptr() == rhs.submanifest_ptr() /* shallow equality */
222 || ( nullptr != lhs.submanifest_ptr()
223 && nullptr != rhs.submanifest_ptr()
224 && *rhs.submanifest_ptr() == *lhs.submanifest_ptr()
225 )
226 )
227 && lhs.catalog() == rhs.catalog();
228}
229
230bool operator!=(const FileManifest& lhs, const FileManifest& rhs) {
231 return lhs.name() != rhs.name()
232 || lhs.data_packet_size() != rhs.data_packet_size()
233 || (lhs.submanifest_ptr() != rhs.submanifest_ptr() /* shallow equality */
234 && (nullptr == lhs.submanifest_ptr()
235 || nullptr == rhs.submanifest_ptr()
236 || *rhs.submanifest_ptr() != *lhs.submanifest_ptr()
237 )
238 )
239 || lhs.catalog() != rhs.catalog();
240}
241
242} // end ntorrent
243} // end ndn