blob: 090b82d40da3bb75a58dcd72495b4ee168de13b4 [file] [log] [blame]
Alexander Afanasyev197e5652014-06-13 16:56:31 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento10b24be2017-07-12 23:23:46 -04002/*
Junxiao Shiebfe4a22018-04-01 23:53:40 +00003 * Copyright (c) 2013-2018 Regents of the University of California.
Alexander Afanasyev197e5652014-06-13 16:56:31 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library 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 * ndn-cxx library 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 ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#include "data.hpp"
Alexander Afanasyev01065fb2014-10-02 13:01:46 -070023#include "encoding/block-helpers.hpp"
Junxiao Shi6938e342017-07-25 21:56:58 +000024#include "util/sha256.hpp"
Alexander Afanasyev197e5652014-06-13 16:56:31 -070025
26namespace ndn {
27
Junxiao Shic2b8d242014-11-04 08:35:29 -070028BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Data>));
29BOOST_CONCEPT_ASSERT((WireEncodable<Data>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070030BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Data>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070031BOOST_CONCEPT_ASSERT((WireDecodable<Data>));
32static_assert(std::is_base_of<tlv::Error, Data::Error>::value,
33 "Data::Error must inherit from tlv::Error");
34
Alexander Afanasyev197e5652014-06-13 16:56:31 -070035Data::Data(const Name& name)
36 : m_name(name)
Junxiao Shi81206d52017-07-23 12:43:22 +000037 , m_content(tlv::Content)
Alexander Afanasyev197e5652014-06-13 16:56:31 -070038{
39}
40
41Data::Data(const Block& wire)
42{
43 wireDecode(wire);
44}
45
Alexander Afanasyev74633892015-02-08 18:08:46 -080046template<encoding::Tag TAG>
Alexander Afanasyev197e5652014-06-13 16:56:31 -070047size_t
Junxiao Shi81206d52017-07-23 12:43:22 +000048Data::wireEncode(EncodingImpl<TAG>& encoder, bool wantUnsignedPortionOnly) const
Alexander Afanasyev197e5652014-06-13 16:56:31 -070049{
Alexander Afanasyev197e5652014-06-13 16:56:31 -070050 // Data ::= DATA-TLV TLV-LENGTH
51 // Name
Junxiao Shi7d9039b2018-04-14 15:56:28 +000052 // MetaInfo?
53 // Content?
Junxiao Shi81206d52017-07-23 12:43:22 +000054 // SignatureInfo
55 // SignatureValue
Alexander Afanasyev197e5652014-06-13 16:56:31 -070056
Junxiao Shi81206d52017-07-23 12:43:22 +000057 size_t totalLength = 0;
Alexander Afanasyev197e5652014-06-13 16:56:31 -070058
Junxiao Shi81206d52017-07-23 12:43:22 +000059 // SignatureValue
60 if (!wantUnsignedPortionOnly) {
61 if (!m_signature) {
62 BOOST_THROW_EXCEPTION(Error("Requested wire format, but Data has not been signed"));
Alexander Afanasyev197e5652014-06-13 16:56:31 -070063 }
Junxiao Shi81206d52017-07-23 12:43:22 +000064 totalLength += encoder.prependBlock(m_signature.getValue());
65 }
Alexander Afanasyev197e5652014-06-13 16:56:31 -070066
67 // SignatureInfo
Alexander Afanasyev74633892015-02-08 18:08:46 -080068 totalLength += encoder.prependBlock(m_signature.getInfo());
Alexander Afanasyev197e5652014-06-13 16:56:31 -070069
70 // Content
Alexander Afanasyev74633892015-02-08 18:08:46 -080071 totalLength += encoder.prependBlock(getContent());
Alexander Afanasyev197e5652014-06-13 16:56:31 -070072
73 // MetaInfo
Alexander Afanasyev74633892015-02-08 18:08:46 -080074 totalLength += getMetaInfo().wireEncode(encoder);
Alexander Afanasyev197e5652014-06-13 16:56:31 -070075
76 // Name
Alexander Afanasyev74633892015-02-08 18:08:46 -080077 totalLength += getName().wireEncode(encoder);
Alexander Afanasyev197e5652014-06-13 16:56:31 -070078
Junxiao Shi81206d52017-07-23 12:43:22 +000079 if (!wantUnsignedPortionOnly) {
80 totalLength += encoder.prependVarNumber(totalLength);
81 totalLength += encoder.prependVarNumber(tlv::Data);
82 }
Alexander Afanasyev197e5652014-06-13 16:56:31 -070083 return totalLength;
84}
85
Alexander Afanasyev15f67312014-07-22 15:11:09 -070086template size_t
Davide Pesavento88a0d812017-08-19 21:31:42 -040087Data::wireEncode<encoding::EncoderTag>(EncodingBuffer&, bool) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -070088
89template size_t
Davide Pesavento88a0d812017-08-19 21:31:42 -040090Data::wireEncode<encoding::EstimatorTag>(EncodingEstimator&, bool) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -070091
Alexander Afanasyev197e5652014-06-13 16:56:31 -070092const Block&
93Data::wireEncode(EncodingBuffer& encoder, const Block& signatureValue) const
94{
95 size_t totalLength = encoder.size();
96 totalLength += encoder.appendBlock(signatureValue);
97
Davide Pesavento9bd4d982015-05-13 14:31:19 +020098 encoder.prependVarNumber(totalLength);
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060099 encoder.prependVarNumber(tlv::Data);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700100
101 const_cast<Data*>(this)->wireDecode(encoder.block());
102 return m_wire;
103}
104
105const Block&
106Data::wireEncode() const
107{
108 if (m_wire.hasWire())
109 return m_wire;
110
111 EncodingEstimator estimator;
112 size_t estimatedSize = wireEncode(estimator);
113
114 EncodingBuffer buffer(estimatedSize, 0);
115 wireEncode(buffer);
116
117 const_cast<Data*>(this)->wireDecode(buffer.block());
118 return m_wire;
119}
120
121void
122Data::wireDecode(const Block& wire)
123{
124 m_wire = wire;
125 m_wire.parse();
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000126 bool hasName = false, hasSigInfo = false;
127 m_name.clear();
128 m_metaInfo = MetaInfo();
129 m_content = Block(tlv::Content);
130 m_signature = Signature();
131 m_fullName.clear();
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700132
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000133 int lastEle = 0; // last recognized element index, in spec order
134 for (const Block& ele : m_wire.elements()) {
135 switch (ele.type()) {
136 case tlv::Name: {
137 if (lastEle >= 1) {
138 BOOST_THROW_EXCEPTION(Error("Name element is out of order"));
139 }
140 hasName = true;
141 m_name.wireDecode(ele);
142 lastEle = 1;
143 break;
144 }
145 case tlv::MetaInfo: {
146 if (lastEle >= 2) {
147 BOOST_THROW_EXCEPTION(Error("MetaInfo element is out of order"));
148 }
149 m_metaInfo.wireDecode(ele);
150 lastEle = 2;
151 break;
152 }
153 case tlv::Content: {
154 if (lastEle >= 3) {
155 BOOST_THROW_EXCEPTION(Error("Content element is out of order"));
156 }
157 m_content = ele;
158 lastEle = 3;
159 break;
160 }
161 case tlv::SignatureInfo: {
162 if (lastEle >= 4) {
163 BOOST_THROW_EXCEPTION(Error("SignatureInfo element is out of order"));
164 }
165 hasSigInfo = true;
166 m_signature.setInfo(ele);
167 lastEle = 4;
168 break;
169 }
170 case tlv::SignatureValue: {
171 if (lastEle >= 5) {
172 BOOST_THROW_EXCEPTION(Error("SignatureValue element is out of order"));
173 }
174 m_signature.setValue(ele);
175 lastEle = 5;
176 break;
177 }
178 default: {
179 if (tlv::isCriticalType(ele.type())) {
180 BOOST_THROW_EXCEPTION(Error("unrecognized element of critical type " +
181 to_string(ele.type())));
182 }
183 break;
184 }
185 }
186 }
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700187
Junxiao Shi7d9039b2018-04-14 15:56:28 +0000188 if (!hasName) {
189 BOOST_THROW_EXCEPTION(Error("Name element is missing"));
190 }
191 if (!hasSigInfo) {
192 BOOST_THROW_EXCEPTION(Error("SignatureInfo element is missing"));
Junxiao Shi81206d52017-07-23 12:43:22 +0000193 }
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700194}
195
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700196const Name&
197Data::getFullName() const
198{
199 if (m_fullName.empty()) {
200 if (!m_wire.hasWire()) {
Junxiao Shi81206d52017-07-23 12:43:22 +0000201 BOOST_THROW_EXCEPTION(Error("Cannot compute full name because Data has no wire encoding (not signed)"));
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700202 }
203 m_fullName = m_name;
Davide Pesavento10b24be2017-07-12 23:23:46 -0400204 m_fullName.appendImplicitSha256Digest(util::Sha256::computeDigest(m_wire.wire(), m_wire.size()));
Alexander Afanasyev3b703102014-06-13 17:01:14 -0700205 }
206
207 return m_fullName;
208}
209
Junxiao Shi81206d52017-07-23 12:43:22 +0000210void
211Data::resetWire()
212{
213 m_wire.reset();
214 m_fullName.clear();
215}
216
217Data&
218Data::setName(const Name& name)
219{
220 resetWire();
221 m_name = name;
222 return *this;
223}
224
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700225Data&
226Data::setMetaInfo(const MetaInfo& metaInfo)
227{
Junxiao Shi81206d52017-07-23 12:43:22 +0000228 resetWire();
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700229 m_metaInfo = metaInfo;
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700230 return *this;
231}
232
233const Block&
234Data::getContent() const
235{
Junxiao Shi81206d52017-07-23 12:43:22 +0000236 if (!m_content.hasWire()) {
237 const_cast<Block&>(m_content).encode();
238 }
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700239 return m_content;
240}
241
242Data&
Junxiao Shi81206d52017-07-23 12:43:22 +0000243Data::setContent(const Block& block)
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700244{
Junxiao Shi81206d52017-07-23 12:43:22 +0000245 resetWire();
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700246
Junxiao Shi81206d52017-07-23 12:43:22 +0000247 if (block.type() == tlv::Content) {
248 m_content = block;
249 }
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700250 else {
Junxiao Shi81206d52017-07-23 12:43:22 +0000251 m_content = Block(tlv::Content, block);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700252 }
253
254 return *this;
255}
256
257Data&
Junxiao Shi81206d52017-07-23 12:43:22 +0000258Data::setContent(const uint8_t* value, size_t valueSize)
259{
260 resetWire();
261 m_content = makeBinaryBlock(tlv::Content, value, valueSize);
262 return *this;
263}
264
265Data&
266Data::setContent(const ConstBufferPtr& value)
267{
268 resetWire();
269 m_content = Block(tlv::Content, value);
270 return *this;
271}
272
273Data&
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700274Data::setSignature(const Signature& signature)
275{
Junxiao Shi81206d52017-07-23 12:43:22 +0000276 resetWire();
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700277 m_signature = signature;
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700278 return *this;
279}
280
281Data&
282Data::setSignatureValue(const Block& value)
283{
Junxiao Shi81206d52017-07-23 12:43:22 +0000284 resetWire();
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700285 m_signature.setValue(value);
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700286 return *this;
287}
288
Junxiao Shi81206d52017-07-23 12:43:22 +0000289Data&
290Data::setContentType(uint32_t type)
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700291{
Junxiao Shi81206d52017-07-23 12:43:22 +0000292 resetWire();
293 m_metaInfo.setType(type);
294 return *this;
295}
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700296
Junxiao Shi81206d52017-07-23 12:43:22 +0000297Data&
Junxiao Shiebfe4a22018-04-01 23:53:40 +0000298Data::setFreshnessPeriod(time::milliseconds freshnessPeriod)
Junxiao Shi81206d52017-07-23 12:43:22 +0000299{
300 resetWire();
301 m_metaInfo.setFreshnessPeriod(freshnessPeriod);
302 return *this;
303}
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700304
Junxiao Shi81206d52017-07-23 12:43:22 +0000305Data&
Junxiao Shiebfe4a22018-04-01 23:53:40 +0000306Data::setFinalBlock(optional<name::Component> finalBlockId)
307{
308 resetWire();
309 m_metaInfo.setFinalBlock(std::move(finalBlockId));
310 return *this;
311}
312
313name::Component
314Data::getFinalBlockId() const
315{
316 return m_metaInfo.getFinalBlockId();
317}
318
319Data&
Junxiao Shi81206d52017-07-23 12:43:22 +0000320Data::setFinalBlockId(const name::Component& finalBlockId)
321{
322 resetWire();
323 m_metaInfo.setFinalBlockId(finalBlockId);
324 return *this;
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700325}
326
327bool
Junxiao Shi81206d52017-07-23 12:43:22 +0000328operator==(const Data& lhs, const Data& rhs)
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700329{
Junxiao Shi81206d52017-07-23 12:43:22 +0000330 return lhs.getName() == rhs.getName() &&
331 lhs.getMetaInfo() == rhs.getMetaInfo() &&
332 lhs.getContent() == rhs.getContent() &&
333 lhs.getSignature() == rhs.getSignature();
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700334}
335
336std::ostream&
337operator<<(std::ostream& os, const Data& data)
338{
339 os << "Name: " << data.getName() << "\n";
340 os << "MetaInfo: " << data.getMetaInfo() << "\n";
341 os << "Content: (size: " << data.getContent().value_size() << ")\n";
Junxiao Shi81206d52017-07-23 12:43:22 +0000342 os << "Signature: (type: " << data.getSignature().getType()
343 << ", value_length: "<< data.getSignature().getValue().value_size() << ")";
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700344 os << std::endl;
345
346 return os;
347}
348
Alexander Afanasyev197e5652014-06-13 16:56:31 -0700349} // namespace ndn