blob: 3daf4978b5b28eee1cd212527c5d6c185fdcb7ef [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07002/**
Alexander Afanasyevaf99f462015-01-19 21:43:09 -08003 * Copyright (c) 2013-2015 Regents of the University of California.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08004 *
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07005 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * 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.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080022 */
23
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070024#ifndef NDN_ENCODING_BLOCK_HPP
25#define NDN_ENCODING_BLOCK_HPP
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080026
Alexander Afanasyev19508852014-01-29 01:01:51 -080027#include "../common.hpp"
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080028
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080029#include "buffer.hpp"
30#include "tlv.hpp"
31
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -070032namespace boost {
33namespace asio {
34class const_buffer;
35} // namespace asio
36} // namespace boost
37
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080038namespace ndn {
39
Alexander Afanasyev233750e2014-02-16 00:50:07 -080040template<bool> class EncodingImpl;
41typedef EncodingImpl<true> EncodingBuffer;
42
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070043/** @brief Class representing a wire element of NDN-TLV packet format
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080044 */
45class Block
46{
47public:
Alexander Afanasyev8ea763d2014-02-06 20:32:52 -080048 typedef std::vector<Block> element_container;
49 typedef element_container::iterator element_iterator;
50 typedef element_container::const_iterator element_const_iterator;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080051
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060052 class Error : public tlv::Error
Alexander Afanasyev937aa782014-03-21 13:17:57 -070053 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -070054 public:
55 explicit
56 Error(const std::string& what)
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060057 : tlv::Error(what)
Alexander Afanasyeva465e972014-03-22 17:21:49 -070058 {
59 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -070060 };
61
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070062public: // constructor, creation, assignment
63 /** @brief Create an empty Block
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080064 */
65 Block();
66
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070067 /** @brief Create a Block based on EncodingBuffer object
Alexander Afanasyev15151312014-02-16 00:53:51 -080068 */
69 explicit
70 Block(const EncodingBuffer& buffer);
Alexander Afanasyev937aa782014-03-21 13:17:57 -070071
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070072 /** @brief Create a Block from the raw buffer with Type-Length parsing
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080073 */
Alexander Afanasyev197e5652014-06-13 16:56:31 -070074 explicit
Alexander Afanasyev937aa782014-03-21 13:17:57 -070075 Block(const ConstBufferPtr& buffer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080076
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070077 /** @brief Create a Block from a buffer, directly specifying boundaries
78 * of the block within the buffer
Alexander Afanasyev187bc482014-02-06 15:04:04 -080079 *
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070080 * This overload will automatically detect type and position of the value within the block
Alexander Afanasyev187bc482014-02-06 15:04:04 -080081 */
Alexander Afanasyev937aa782014-03-21 13:17:57 -070082 Block(const ConstBufferPtr& buffer,
83 const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080084 bool verifyLength = true);
Alexander Afanasyev937aa782014-03-21 13:17:57 -070085
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070086 /** @brief Create a Block from the raw buffer with Type-Length parsing
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080087 */
Alexander Afanasyev937aa782014-03-21 13:17:57 -070088 Block(const uint8_t* buffer, size_t maxlength);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080089
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070090 /** @brief Create a Block from the raw buffer with Type-Length parsing
91 */
Alexander Afanasyev937aa782014-03-21 13:17:57 -070092 Block(const void* buffer, size_t maxlength);
Yingdi Yu27158392014-01-20 13:04:20 -080093
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070094 /** @brief Create a Block from the wire buffer (no parsing)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080095 *
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070096 * This overload does not do any parsing
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080097 */
Alexander Afanasyev937aa782014-03-21 13:17:57 -070098 Block(const ConstBufferPtr& wire,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080099 uint32_t type,
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700100 const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
101 const Buffer::const_iterator& valueBegin, const Buffer::const_iterator& valueEnd);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800102
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700103 /** @brief Create Block of a specific type with empty wire buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800104 */
Alexander Afanasyevf42ce132014-01-07 13:32:30 -0800105 explicit
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800106 Block(uint32_t type);
107
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700108 /** @brief Create a Block of a specific type with the specified value
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800109 *
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700110 * The underlying buffer holds only value Additional operations are needed
111 * to construct wire encoding, one need to prepend the wire buffer with type
112 * and value-length VAR-NUMBERs
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800113 */
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700114 Block(uint32_t type, const ConstBufferPtr& value);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800115
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700116 /** @brief Create a nested Block of a specific type with the specified value
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800117 *
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700118 * The underlying buffer holds only value. Additional operations are needed
119 * to construct wire encoding, one need to prepend the wire buffer with type
120 * and value-length VAR-NUMBERs
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800121 */
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700122 Block(uint32_t type, const Block& value);
123
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700124 /** @brief Create a Block from an input stream
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700125 */
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700126 static Block
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700127 fromStream(std::istream& is);
128
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700129 /** @brief Try to construct block from Buffer, referencing data block pointed by wire
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700130 *
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700131 * This method does not throw upon decoding error.
132 * @return true if Block successfully created, false if block cannot be created
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700133 */
134 static bool
135 fromBuffer(const ConstBufferPtr& wire, size_t offset, Block& block);
136
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700137 /** @brief Try to construct block from Buffer, referencing data block pointed by wire
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700138 *
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700139 * This method does not throw upon decoding error.
140 * @return true if Block successfully created, false if block cannot be created
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700141 */
142 static bool
143 fromBuffer(const uint8_t* buffer, size_t maxSize, Block& block);
Alexander Afanasyev196b9aa2014-01-31 17:19:16 -0800144
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700145public: // wire format
146 /** @brief Check if the Block is empty
Alexander Afanasyev196b9aa2014-01-31 17:19:16 -0800147 */
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700148 bool
Alexander Afanasyev196b9aa2014-01-31 17:19:16 -0800149 empty() const;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700150
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700151 /** @brief Check if the Block has fully encoded wire
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800152 */
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700153 bool
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800154 hasWire() const;
155
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700156 /** @brief Reset wire buffer of the element
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800157 */
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700158 void
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800159 reset();
160
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700161 /** @brief Reset wire buffer but keep sub elements (if any)
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800162 */
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700163 void
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800164 resetWire();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800165
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700166 Buffer::const_iterator
167 begin() const;
168
169 Buffer::const_iterator
170 end() const;
171
172 const uint8_t*
173 wire() const;
174
175 size_t
176 size() const;
177
178public: // type and value
179 uint32_t
180 type() const;
181
182 /** @brief Check if the Block has value block (no type and length are encoded)
183 */
184 bool
185 hasValue() const;
186
187 Buffer::const_iterator
188 value_begin() const;
189
190 Buffer::const_iterator
191 value_end() const;
192
193 const uint8_t*
194 value() const;
195
196 size_t
197 value_size() const;
198
199public: // sub elements
200 /** @brief Parse wire buffer into subblocks
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800201 *
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700202 * This method is not really const, but it does not modify any data. It simply
203 * parses contents of the buffer into subblocks
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800204 */
205 void
206 parse() const;
207
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700208 /** @brief Encode subblocks into wire buffer
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800209 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800210 void
211 encode();
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700212
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700213 /** @brief Get the first subelement of the requested type
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800214 */
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700215 const Block&
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800216 get(uint32_t type) const;
217
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700218 element_const_iterator
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800219 find(uint32_t type) const;
220
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700221 void
Alexander Afanasyevf5c35ae2014-01-17 16:06:31 -0800222 remove(uint32_t type);
223
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700224 element_iterator
Alexander Afanasyevf5c35ae2014-01-17 16:06:31 -0800225 erase(element_iterator position);
226
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700227 element_iterator
Alexander Afanasyevf5c35ae2014-01-17 16:06:31 -0800228 erase(element_iterator first, element_iterator last);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700229
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700230 void
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700231 push_back(const Block& element);
232
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700233 /** @brief Get all subelements
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800234 */
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700235 const element_container&
236 elements() const;
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800237
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700238 element_const_iterator
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800239 elements_begin() const;
240
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700241 element_const_iterator
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800242 elements_end() const;
243
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700244 size_t
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800245 elements_size() const;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700246
Yingdi Yu4270f202014-01-28 14:19:16 -0800247 Block
248 blockFromValue() const;
249
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700250public: // EqualityComparable concept
251 bool
252 operator==(const Block& other) const;
253
254 bool
255 operator!=(const Block& other) const;
256
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700257public: // ConvertibleToConstBuffer
258 operator boost::asio::const_buffer() const;
259
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800260protected:
261 ConstBufferPtr m_buffer;
262
263 uint32_t m_type;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700264
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800265 Buffer::const_iterator m_begin;
266 Buffer::const_iterator m_end;
267 uint32_t m_size;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700268
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800269 Buffer::const_iterator m_value_begin;
270 Buffer::const_iterator m_value_end;
271
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800272 mutable element_container m_subBlocks;
Alexander Afanasyev233750e2014-02-16 00:50:07 -0800273 friend class EncodingImpl<true>;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800274};
275
276////////////////////////////////////////////////////////////////////////////////
277////////////////////////////////////////////////////////////////////////////////
278////////////////////////////////////////////////////////////////////////////////
279
280inline bool
Alexander Afanasyev196b9aa2014-01-31 17:19:16 -0800281Block::empty() const
282{
283 return m_type == std::numeric_limits<uint32_t>::max();
284}
285
Alexander Afanasyev196b9aa2014-01-31 17:19:16 -0800286inline bool
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800287Block::hasWire() const
288{
289 return m_buffer && (m_begin != m_end);
290}
291
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800292inline Buffer::const_iterator
293Block::begin() const
294{
295 if (!hasWire())
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700296 throw Error("Underlying wire buffer is empty");
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800297
298 return m_begin;
299}
300
301inline Buffer::const_iterator
302Block::end() const
303{
304 if (!hasWire())
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700305 throw Error("Underlying wire buffer is empty");
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800306
307 return m_end;
308}
309
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700310inline const uint8_t*
311Block::wire() const
312{
313 if (!hasWire())
314 throw Error("(Block::wire) Underlying wire buffer is empty");
315
316 return &*m_begin;
317}
318
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800319inline size_t
320Block::size() const
321{
322 if (hasWire() || hasValue()) {
323 return m_size;
324 }
325 else
326 throw Error("Block size cannot be determined (undefined block size)");
327}
328
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700329inline uint32_t
330Block::type() const
331{
332 return m_type;
333}
334
335inline bool
336Block::hasValue() const
337{
338 return static_cast<bool>(m_buffer);
339}
340
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800341inline Buffer::const_iterator
342Block::value_begin() const
343{
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800344 return m_value_begin;
345}
346
347inline Buffer::const_iterator
348Block::value_end() const
349{
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800350 return m_value_end;
351}
352
353inline const uint8_t*
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800354Block::value() const
355{
356 if (!hasValue())
Alexander Afanasyev380420b2014-02-09 20:52:29 -0800357 return 0;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700358
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800359 return &*m_value_begin;
360}
361
362inline size_t
363Block::value_size() const
364{
365 if (!hasValue())
Alexander Afanasyev8ea763d2014-02-06 20:32:52 -0800366 return 0;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800367
368 return m_value_end - m_value_begin;
369}
370
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700371inline Block::element_iterator
372Block::erase(Block::element_iterator position)
373{
374 resetWire();
375 return m_subBlocks.erase(position);
376}
377
378inline Block::element_iterator
379Block::erase(Block::element_iterator first, Block::element_iterator last)
380{
381 resetWire();
382 return m_subBlocks.erase(first, last);
383}
384
385inline void
386Block::push_back(const Block& element)
387{
388 resetWire();
389 m_subBlocks.push_back(element);
390}
391
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800392inline const Block::element_container&
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700393Block::elements() const
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800394{
395 return m_subBlocks;
396}
397
398inline Block::element_const_iterator
399Block::elements_begin() const
400{
401 return m_subBlocks.begin();
402}
403
404inline Block::element_const_iterator
405Block::elements_end() const
406{
407 return m_subBlocks.end();
408}
409
410inline size_t
411Block::elements_size() const
412{
413 return m_subBlocks.size();
414}
415
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700416inline bool
Junxiao Shiaf8eeea2014-03-31 20:10:56 -0700417Block::operator!=(const Block& other) const
418{
419 return !this->operator==(other);
420}
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800421
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700422} // namespace ndn
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800423
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700424#endif // NDN_ENCODING_BLOCK_HPP