blob: 5130b03eec2fe806f85a25e33074e43bc5c40ddd [file] [log] [blame]
Jeff Thompson25b4e612013-10-10 16:03:24 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
Jeff Thompson5cae5e52013-07-10 19:41:20 -07002/**
Jeff Thompson7687dc02013-09-13 11:54:07 -07003 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
Jeff Thompson5cae5e52013-07-10 19:41:20 -07005 * See COPYING for copyright and distribution information.
6 */
7
Jeff Thompson56ec9e22013-08-02 11:34:07 -07008#ifndef NDN_DATA_HPP
Jeff Thompsona0d18c92013-08-06 13:55:32 -07009#define NDN_DATA_HPP
Jeff Thompson5cae5e52013-07-10 19:41:20 -070010
Jeff Thompson46bd45f2013-08-08 16:46:41 -070011#include "common.hpp"
Jeff Thompson53412192013-08-06 13:35:50 -070012#include "name.hpp"
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -080013#include "encoding/block.hpp"
Jeff Thompson25b4e612013-10-10 16:03:24 -070014
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080015#include "signature.hpp"
16#include "meta-info.hpp"
17#include "key-locator.hpp"
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080018#include "management/nfd-local-control-header.hpp"
Jeff Thompson5cae5e52013-07-10 19:41:20 -070019
20namespace ndn {
Jeff Thompson5cae5e52013-07-10 19:41:20 -070021
Alexander Afanasyev0222fba2014-02-09 23:16:02 -080022class Data : public enable_shared_from_this<Data>
23{
Jeff Thompson5cae5e52013-07-10 19:41:20 -070024public:
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080025 struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
26
Jeff Thompson20af0732013-09-12 17:01:45 -070027 /**
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080028 * @brief Create an empty Data object
Jeff Thompson20af0732013-09-12 17:01:45 -070029 */
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080030 inline
31 Data();
32
Jeff Thompson20af0732013-09-12 17:01:45 -070033 /**
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080034 * @brief Create a new Data object with the given name
Jeff Thompson20af0732013-09-12 17:01:45 -070035 * @param name A reference to the name which is copied.
36 */
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080037 inline
38 Data(const Name& name);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080039
40 /**
41 * @brief Create a new Data object from wire encoding
42 */
43 explicit
44 Data(const Block& wire)
45 {
46 wireDecode(wire);
47 }
Jeff Thompson25bfdca2013-10-16 17:05:41 -070048
49 /**
Alexander Afanasyev809805d2014-02-17 17:20:33 -080050 * @brief The destructor
Jeff Thompsonc69163b2013-10-12 13:49:50 -070051 */
Alexander Afanasyev809805d2014-02-17 17:20:33 -080052 inline
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080053 ~Data();
Jeff Thompsonc69163b2013-10-12 13:49:50 -070054
55 /**
Alexander Afanasyev809805d2014-02-17 17:20:33 -080056 * @brief Fast encoding or block size estimation
Jeff Thompsonb7aefa002013-09-16 18:22:00 -070057 */
Alexander Afanasyev809805d2014-02-17 17:20:33 -080058 template<bool T>
59 inline size_t
60 wireEncode(EncodingImpl<T> &block, bool unsignedPortion = false) const;
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -080061
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080062 /**
Alexander Afanasyev809805d2014-02-17 17:20:33 -080063 * @brief Encode to a wire format
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080064 */
Alexander Afanasyev809805d2014-02-17 17:20:33 -080065 inline const Block&
66 wireEncode() const;
67
68 /**
69 * @brief Decode from the wire format
70 */
71 inline void
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -080072 wireDecode(const Block &wire);
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -080073
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080074 /**
75 * @brief Check if already has wire
76 */
77 inline bool
78 hasWire() const;
79
Alexander Afanasyev809805d2014-02-17 17:20:33 -080080 ////////////////////////////////////////////////////////////////////
81
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080082 inline const Name&
83 getName() const;
Jeff Thompson5cae5e52013-07-10 19:41:20 -070084
85 /**
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080086 * @brief Set name to a copy of the given Name.
87 *
Jeff Thompson0cd8c4a2013-09-13 17:46:40 -070088 * @param name The Name which is copied.
Jeff Thompson6d591972013-10-17 11:16:32 -070089 * @return This Data so that you can chain calls to update values.
Jeff Thompson0cd8c4a2013-09-13 17:46:40 -070090 */
Alexander Afanasyeva61757b2014-01-03 15:09:29 -080091 inline void
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080092 setName(const Name& name);
93
Alexander Afanasyev809805d2014-02-17 17:20:33 -080094 //
95
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -080096 inline const MetaInfo&
97 getMetaInfo() const;
Jeff Thompson46bd45f2013-08-08 16:46:41 -070098
Jeff Thompson0cd8c4a2013-09-13 17:46:40 -070099 /**
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800100 * @brief Set metaInfo to a copy of the given MetaInfo.
Jeff Thompson0cd8c4a2013-09-13 17:46:40 -0700101 * @param metaInfo The MetaInfo which is copied.
Jeff Thompson6d591972013-10-17 11:16:32 -0700102 * @return This Data so that you can chain calls to update values.
Jeff Thompson0cd8c4a2013-09-13 17:46:40 -0700103 */
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800104 inline void
105 setMetaInfo(const MetaInfo& metaInfo);
Jeff Thompson46bd45f2013-08-08 16:46:41 -0700106
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800107 //
108
109 ///////////////////////////////////////////////////////////////
110 ///////////////////////////////////////////////////////////////
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800111 ///////////////////////////////////////////////////////////////
112 // MetaInfo proxy methods
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800113
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800114 inline uint32_t
115 getContentType() const;
116
117 inline void
118 setContentType(uint32_t type);
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800119
120 //
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800121
122 inline Milliseconds
123 getFreshnessPeriod() const;
124
125 inline void
126 setFreshnessPeriod(Milliseconds freshnessPeriod);
Alexander Afanasyev95b0e342014-02-12 21:34:44 -0800127
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800128 //
129
Alexander Afanasyev95b0e342014-02-12 21:34:44 -0800130 inline const name::Component&
131 getFinalBlockId() const;
132
133 inline void
134 setFinalBlockId(const name::Component& finalBlockId);
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800135
136 //
137 ///////////////////////////////////////////////////////////////
138 ///////////////////////////////////////////////////////////////
139 ///////////////////////////////////////////////////////////////
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800140
141 /**
142 * @brief Get content Block
143 *
144 * To access content value, one can use value()/value_size() or
145 * value_begin()/value_end() methods of the Block class
146 */
147 inline const Block&
148 getContent() const;
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800149
Jeff Thompson0899c0f2013-09-12 12:15:31 -0700150 /**
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800151 * @brief Set the content to a copy of the data in the vector.
Jeff Thompson0899c0f2013-09-12 12:15:31 -0700152 * @param content A vector whose contents are copied.
Jeff Thompson6d591972013-10-17 11:16:32 -0700153 * @return This Data so that you can chain calls to update values.
Jeff Thompson0899c0f2013-09-12 12:15:31 -0700154 */
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800155 inline void
156 setContent(const uint8_t* content, size_t contentLength);
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800157
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800158 inline void
159 setContent(const Block& content);
160
161 inline void
162 setContent(const ConstBufferPtr &contentValue);
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800163
164 //
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800165
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800166 inline const Signature&
167 getSignature() const;
168
169 /**
170 * @brief Set the signature to a copy of the given signature.
171 * @param signature The signature object which is cloned.
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800172 */
Alexander Afanasyevad39b182014-01-03 15:38:58 -0800173 inline void
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800174 setSignature(const Signature& signature);
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800175
Alexander Afanasyevad39b182014-01-03 15:38:58 -0800176 inline void
177 setSignatureValue(const Block &value);
Yingdi Yua4e57672014-02-06 11:16:17 -0800178
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800179 ///////////////////////////////////////////////////////////////
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800180
181 nfd::LocalControlHeader&
182 getLocalControlHeader();
183
184 const nfd::LocalControlHeader&
185 getLocalControlHeader() const;
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800186
Yingdi Yua4e57672014-02-06 11:16:17 -0800187 inline uint64_t
188 getIncomingFaceId() const;
189
190 inline void
191 setIncomingFaceId(uint64_t incomingFaceId);
Alexander Afanasyevad39b182014-01-03 15:38:58 -0800192
Jeff Thompson5cae5e52013-07-10 19:41:20 -0700193private:
Jeff Thompsonb7aefa002013-09-16 18:22:00 -0700194 /**
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800195 * @brief Clear the wire encoding.
Jeff Thompsonb7aefa002013-09-16 18:22:00 -0700196 */
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800197 inline void
Jeff Thompson0050abe2013-09-17 12:50:25 -0700198 onChanged();
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800199
200private:
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800201 Name m_name;
202 MetaInfo m_metaInfo;
203 mutable Block m_content;
204 Signature m_signature;
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800205
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800206 mutable Block m_wire;
Yingdi Yua4e57672014-02-06 11:16:17 -0800207
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800208 nfd::LocalControlHeader m_localControlHeader;
209 friend class nfd::LocalControlHeader;
Jeff Thompson5cae5e52013-07-10 19:41:20 -0700210};
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800211
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800212inline
213Data::Data()
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800214 : m_content(Tlv::Content) // empty content
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800215{
216}
217
218inline
219Data::Data(const Name& name)
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800220 : m_name(name)
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800221{
222}
223
224inline
225Data::~Data()
226{
227}
228
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800229template<bool T>
230inline size_t
231Data::wireEncode(EncodingImpl<T> &block, bool unsignedPortion/* = false*/) const
232{
233 size_t total_len = 0;
234
235 // Data ::= DATA-TLV TLV-LENGTH
236 // Name
237 // MetaInfo
238 // Content
239 // Signature
240
241 // (reverse encoding)
242
243 if (!unsignedPortion && !m_signature)
244 {
245 throw Error("Requested wire format, but data packet has not been signed yet");
246 }
247
248 if (!unsignedPortion)
249 {
250 // SignatureValue
251 total_len += prependBlock(block, m_signature.getValue());
252 }
253
254 // SignatureInfo
255 total_len += prependBlock(block, m_signature.getInfo());
256
257 // Content
258 total_len += prependBlock(block, getContent());
259
260 // MetaInfo
261 total_len += getMetaInfo().wireEncode(block);
262
263 // Name
264 total_len += getName().wireEncode(block);
265
266 if (!unsignedPortion)
267 {
268 total_len += block.prependVarNumber (total_len);
269 total_len += block.prependVarNumber (Tlv::Data);
270 }
271 return total_len;
272}
273
274inline const Block &
275Data::wireEncode() const
276{
277 if (m_wire.hasWire())
278 return m_wire;
279
280 EncodingEstimator estimator;
281 size_t estimatedSize = wireEncode(estimator);
282
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800283 EncodingBuffer buffer(estimatedSize, 0);
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800284 wireEncode(buffer);
285
286 const_cast<Data*>(this)->wireDecode(buffer.block());
287 return m_wire;
288}
289
290/**
291 * Decode the input using a particular wire format and update this Data.
292 * @param input The input byte array to be decoded.
293 */
294void
295Data::wireDecode(const Block &wire)
296{
297 m_wire = wire;
298 m_wire.parse();
299
300 // Data ::= DATA-TLV TLV-LENGTH
301 // Name
302 // MetaInfo
303 // Content
304 // Signature
305
306 // Name
307 m_name.wireDecode(m_wire.get(Tlv::Name));
308
309 // MetaInfo
310 m_metaInfo.wireDecode(m_wire.get(Tlv::MetaInfo));
311
312 // Content
313 m_content = m_wire.get(Tlv::Content);
314
315 ///////////////
316 // Signature //
317 ///////////////
318
319 // SignatureInfo
320 m_signature.setInfo(m_wire.get(Tlv::SignatureInfo));
321
322 // SignatureValue
323 Block::element_const_iterator val = m_wire.find(Tlv::SignatureValue);
324 if (val != m_wire.elements_end())
325 m_signature.setValue(*val);
326}
327
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800328inline bool
329Data::hasWire() const
330{
331 return m_wire.hasWire();
332}
333
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800334inline const Name&
335Data::getName() const
336{
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800337 return m_name;
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800338}
339
340inline void
341Data::setName(const Name& name)
342{
343 onChanged();
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800344 m_name = name;
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800345}
346
347inline const MetaInfo&
348Data::getMetaInfo() const
349{
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800350 return m_metaInfo;
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800351}
352
353inline void
354Data::setMetaInfo(const MetaInfo& metaInfo)
355{
356 onChanged();
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800357 m_metaInfo = metaInfo;
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800358}
359
360inline uint32_t
361Data::getContentType() const
362{
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800363 return m_metaInfo.getType();
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800364}
365
366inline void
367Data::setContentType(uint32_t type)
368{
369 onChanged();
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800370 m_metaInfo.setType(type);
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800371}
372
373inline Milliseconds
374Data::getFreshnessPeriod() const
375{
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800376 return m_metaInfo.getFreshnessPeriod();
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800377}
378
379inline void
380Data::setFreshnessPeriod(Milliseconds freshnessPeriod)
381{
382 onChanged();
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800383 m_metaInfo.setFreshnessPeriod(freshnessPeriod);
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800384}
385
Alexander Afanasyev95b0e342014-02-12 21:34:44 -0800386inline const name::Component&
387Data::getFinalBlockId() const
388{
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800389 return m_metaInfo.getFinalBlockId();
Alexander Afanasyev95b0e342014-02-12 21:34:44 -0800390}
391
392inline void
393Data::setFinalBlockId(const name::Component& finalBlockId)
394{
395 onChanged();
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800396 m_metaInfo.setFinalBlockId(finalBlockId);
Alexander Afanasyev95b0e342014-02-12 21:34:44 -0800397}
398
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800399inline const Block&
400Data::getContent() const
401{
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800402 if (m_content.empty())
403 m_content = dataBlock(Tlv::Content, reinterpret_cast<const uint8_t*>(0), 0);
Alexander Afanasyev196b9aa2014-01-31 17:19:16 -0800404
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800405 if (!m_content.hasWire())
406 m_content.encode();
407 return m_content;
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800408}
409
410inline void
411Data::setContent(const uint8_t* content, size_t contentLength)
412{
413 onChanged();
414
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800415 m_content = dataBlock(Tlv::Content, content, contentLength);
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800416}
417
418inline void
419Data::setContent(const ConstBufferPtr &contentValue)
420{
421 onChanged();
422
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800423 m_content = Block(Tlv::Content, contentValue); // not real a wire encoding yet
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800424}
425
426inline void
427Data::setContent(const Block& content)
Alexander Afanasyeve0c02f52013-12-28 20:44:25 -0800428{
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800429 onChanged();
430
Alexander Afanasyeve0c02f52013-12-28 20:44:25 -0800431 if (content.type() == Tlv::Content)
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800432 m_content = content;
Alexander Afanasyeve0c02f52013-12-28 20:44:25 -0800433 else {
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800434 m_content = Block(Tlv::Content, content);
Alexander Afanasyeve0c02f52013-12-28 20:44:25 -0800435 }
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800436}
437
438inline const Signature&
439Data::getSignature() const
440{
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800441 return m_signature;
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800442}
443
Alexander Afanasyevad39b182014-01-03 15:38:58 -0800444inline void
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800445Data::setSignature(const Signature& signature)
446{
447 onChanged();
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800448 m_signature = signature;
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800449}
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800450
Alexander Afanasyevad39b182014-01-03 15:38:58 -0800451inline void
452Data::setSignatureValue(const Block &value)
453{
454 onChanged();
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800455 m_signature.setValue(value);
Alexander Afanasyevad39b182014-01-03 15:38:58 -0800456}
457
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800458//
459
460inline nfd::LocalControlHeader&
461Data::getLocalControlHeader()
462{
463 return m_localControlHeader;
464}
465
466inline const nfd::LocalControlHeader&
467Data::getLocalControlHeader() const
468{
469 return m_localControlHeader;
470}
471
Yingdi Yua4e57672014-02-06 11:16:17 -0800472inline uint64_t
473Data::getIncomingFaceId() const
474{
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800475 return getLocalControlHeader().getIncomingFaceId();
Yingdi Yua4e57672014-02-06 11:16:17 -0800476}
477
478inline void
479Data::setIncomingFaceId(uint64_t incomingFaceId)
480{
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800481 getLocalControlHeader().setIncomingFaceId(incomingFaceId);
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800482 // ! do not reset Data's wire !
Yingdi Yua4e57672014-02-06 11:16:17 -0800483}
Alexander Afanasyevad39b182014-01-03 15:38:58 -0800484
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800485inline void
486Data::onChanged()
487{
Alexander Afanasyev2ba8f662014-01-05 22:53:18 -0800488 // The values have changed, so the wire format is invalidated
489
490 // !!!Note!!! Signature is not invalidated and it is responsibility of
491 // the application to do proper re-signing if necessary
492
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800493 m_wire.reset();
Jeff Thompson5cae5e52013-07-10 19:41:20 -0700494}
495
Alexander Afanasyev809805d2014-02-17 17:20:33 -0800496inline std::ostream&
497operator << (std::ostream &os, const Data &data)
498{
499 os << "Name: " << data.getName() << "\n";
500 os << "MetaInfo: " << data.getMetaInfo() << "\n";
501 os << "Content: (size: " << data.getContent().value_size() << ")\n";
502 os << "Signature: (type: " << data.getSignature().getType() <<
503 ", value_length: "<< data.getSignature().getValue().value_size() << ")";
504 os << std::endl;
505
506 return os;
507}
Alexander Afanasyev4ff3c912014-01-03 15:25:02 -0800508
Alexander Afanasyevfadc97d2014-01-03 13:22:10 -0800509} // namespace ndn
510
Jeff Thompson5cae5e52013-07-10 19:41:20 -0700511#endif