Created inital design for file-manifest structure
Change-Id: Ie578aea9764fb586101dbcb77e41cc6e319f390b
diff --git a/src/file-manifest.cpp b/src/file-manifest.cpp
new file mode 100644
index 0000000..7352699
--- /dev/null
+++ b/src/file-manifest.cpp
@@ -0,0 +1,244 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+* Copyright (c) 2016 Regents of the University of California.
+*
+* This file is part of the nTorrent codebase.
+*
+* nTorrent is free software: you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation, either version 3 of the License, or (at your option) any later version.
+*
+* nTorrent is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received copies of the GNU General Public License and GNU Lesser
+* General Public License along with nTorrent, e.g., in COPYING.md file. If not, see
+* <http://www.gnu.org/licenses/>.
+*
+* See AUTHORS for complete list of nTorrent authors and contributors.
+*/
+#include "file-manifest.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/range/adaptors.hpp>
+#include <boost/throw_exception.hpp>
+
+using std::vector;
+
+namespace ndn {
+namespace ntorrent {
+
+BOOST_CONCEPT_ASSERT((boost::EqualityComparable<FileManifest>));
+BOOST_CONCEPT_ASSERT((WireEncodable<FileManifest>));
+BOOST_CONCEPT_ASSERT((WireDecodable<FileManifest>));
+static_assert(std::is_base_of<Data::Error, FileManifest::Error>::value,
+ "FileManifest::Error should inherit from Data::Error");
+
+void
+FileManifest::wireDecode(const Block& wire)
+{
+ Data::wireDecode(wire);
+ this->decodeContent();
+}
+
+const Block&
+FileManifest::wireEncode()
+{
+ encodeContent();
+ return Data::wireEncode();
+}
+
+template<ndn::encoding::Tag TAG>
+size_t
+FileManifest::encodeContent(ndn::EncodingImpl<TAG>& encoder) const {
+ // FileManifestName ::= NAME-TYPE TLV-LENGTH
+ // Name
+
+ // ManifestContent ::= CONTENT-TYPE TLV-LENGTH
+ // DataPacketName*
+ // CatalogPrefix
+ // DataPacketSize
+ // FileManifestPtr?
+
+ // DataPacketName ::= NAME-TYPE TLV-LENGTH
+ // Name
+
+ // CatalogPrefix ::= NAME-TYPE TLV-LENGTH
+ // Name
+
+ // DataPacketSize ::= CONTENT-TYPE TLV-LENGTH
+ // nonNegativeInteger
+
+ // FileManifestPtr ::= NAME-TYPE TLV-LENGTH
+ // Name
+
+ size_t totalLength = 0;
+
+ vector<Name> suffixCatalog;
+ suffixCatalog.reserve(m_catalog.size());
+ for (auto name: m_catalog) {
+ if (!m_catalogPrefix.isPrefixOf(name)) {
+ BOOST_THROW_EXCEPTION(Error(name.toUri() + "does not have the prefix"
+ + m_catalogPrefix.toUri()));
+ }
+ name = name.getSubName(m_catalogPrefix.size());
+ if (name.empty()) {
+ BOOST_THROW_EXCEPTION(Error("Manifest cannot include empty string"));
+ }
+ suffixCatalog.push_back(name);
+ }
+
+ for (const auto& name : suffixCatalog | boost::adaptors::reversed) {
+ totalLength += name.wireEncode(encoder);
+ }
+
+ totalLength += m_catalogPrefix.wireEncode(encoder);
+
+ totalLength += prependNonNegativeIntegerBlock(encoder, tlv::Content, m_dataPacketSize);
+
+ if (nullptr != m_submanifestPtr) {
+ totalLength += m_submanifestPtr->wireEncode(encoder);
+ }
+
+ totalLength += encoder.prependVarNumber(totalLength);
+ totalLength += encoder.prependVarNumber(tlv::Content);
+ return totalLength;
+
+}
+
+// MANIPULATORS
+void
+FileManifest::push_back(const Name& name)
+{
+ BOOST_ASSERT(name != m_catalogPrefix);
+ BOOST_ASSERT(m_catalogPrefix.isPrefixOf(name));
+ m_catalog.push_back(name);
+}
+
+bool
+FileManifest::remove(const ndn::Name& name) {
+ auto it = std::find(m_catalog.begin(), m_catalog.end(), name);
+ if (m_catalog.end() == it) {
+ return false;
+ }
+ m_catalog.erase(it);
+ return true;
+}
+
+void FileManifest::encodeContent() {
+ // Name
+ // <file_name>/ImplicitDigest
+ // Content
+ // MetaData
+ // DataPtr*
+ // ManifestPointer?
+ //
+ // DataPtr := HashValue
+ // ManifestPtr := HashValue
+ // HashValue := OCTET[32]
+
+ // MetaData := Property*
+ // Property := DataSize | Signature
+ onChanged();
+
+ EncodingEstimator estimator;
+ size_t estimatedSize = encodeContent(estimator);
+
+ EncodingBuffer buffer(estimatedSize, 0);
+ encodeContent(buffer);
+
+ setContentType(tlv::ContentType_Blob);
+ setContent(buffer.block());
+}
+
+void
+FileManifest::decodeContent() {
+ // ManifestContent ::= CONTENT-TYPE TLV-LENGTH
+ // DataPacketName*
+ // CatalogPrefix
+ // DataPacketSize
+ // FileManifestPtr?
+
+
+ // DataPacketName ::= NAME-TYPE TLV-LENGTH
+ // Name
+
+ // CatalogPrefix ::= NAME-TYPE TLV-LENGTH
+ // Name
+
+ // DataPacketSize ::= CONTENT-TYPE TLV-LENGTH
+ // nonNegativeInteger
+
+ // FileManifestPtr ::= NAME-TYPE TLV-LENGTH
+ // Name
+
+ if (getContentType() != tlv::ContentType_Blob) {
+ BOOST_THROW_EXCEPTION(Error("Expected Content Type Blob"));
+ }
+
+ const Block& content = Data::getContent();
+ content.parse();
+
+ auto element = content.elements_begin();
+
+ if (content.elements_end() == element) {
+ BOOST_THROW_EXCEPTION(Error("FileManifest with empty content"));
+ }
+
+ element->parse();
+ Name name(*element);
+
+ // Submanifest ptr
+ if (!name.empty()) {
+ m_submanifestPtr = std::make_shared<Name>(name);
+ ++element;
+ }
+
+ // DataPacketSize
+ m_dataPacketSize = readNonNegativeInteger(*element);
+ ++element;
+
+ // CatalogPrefix
+ m_catalogPrefix = Name(*element);
+ element++;
+
+ // Catalog
+ m_catalog.clear();
+ for (; element != content.elements_end(); ++element) {
+ element->parse();
+ name = m_catalogPrefix;
+ name.append(Name(*element));
+ if (name == m_catalogPrefix) {
+ BOOST_THROW_EXCEPTION(Error("Empty name included in a FileManifest"));
+ }
+ push_back(name);
+ }
+}
+
+bool operator==(const FileManifest& lhs, const FileManifest& rhs) {
+ return lhs.name() == rhs.name()
+ && lhs.data_packet_size() == rhs.data_packet_size()
+ && (lhs.submanifest_ptr() == rhs.submanifest_ptr() /* shallow equality */
+ || ( nullptr != lhs.submanifest_ptr()
+ && nullptr != rhs.submanifest_ptr()
+ && *rhs.submanifest_ptr() == *lhs.submanifest_ptr()
+ )
+ )
+ && lhs.catalog() == rhs.catalog();
+}
+
+bool operator!=(const FileManifest& lhs, const FileManifest& rhs) {
+ return lhs.name() != rhs.name()
+ || lhs.data_packet_size() != rhs.data_packet_size()
+ || (lhs.submanifest_ptr() != rhs.submanifest_ptr() /* shallow equality */
+ && (nullptr == lhs.submanifest_ptr()
+ || nullptr == rhs.submanifest_ptr()
+ || *rhs.submanifest_ptr() != *lhs.submanifest_ptr()
+ )
+ )
+ || lhs.catalog() != rhs.catalog();
+}
+
+} // end ntorrent
+} // end ndn
\ No newline at end of file
diff --git a/src/file-manifest.hpp b/src/file-manifest.hpp
new file mode 100644
index 0000000..0a46574
--- /dev/null
+++ b/src/file-manifest.hpp
@@ -0,0 +1,244 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+* Copyright (c) 2016 Regents of the University of California.
+*
+* This file is part of the nTorrent codebase.
+*
+* nTorrent is free software: you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation, either version 3 of the License, or (at your option) any later version.
+*
+* nTorrent is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received copies of the GNU General Public License and GNU Lesser
+* General Public License along with nTorrent, e.g., in COPYING.md file. If not, see
+* <http://www.gnu.org/licenses/>.
+*
+* See AUTHORS for complete list of nTorrent authors and contributors.
+*/
+#ifndef INCLUDED_FILE_MANIFEST_HPP
+#define INCLUDED_FILE_MANIFEST_HPP
+
+#include <cstring>
+#include <list>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <ndn-cxx/data.hpp>
+#include <ndn-cxx/name.hpp>
+
+namespace ndn {
+namespace ntorrent {
+
+class FileManifest : public Data {
+/**
+* \class FileManifest
+*
+* \brief A value semantic type for File manifests
+*
+*/
+ public:
+ // TYPES
+ class Error : public Data::Error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : Data::Error(what)
+ {
+ }
+ };
+
+ public:
+ // CREATORS
+ FileManifest() = delete;
+
+ ~FileManifest() = default;
+ /// Destroy this object
+
+ FileManifest(const Name& name,
+ size_t dataPacketSize,
+ const Name& commonPrefix,
+ const std::vector<Name>& catalog = std::vector<Name>(),
+ std::shared_ptr<Name> subManifestPtr = nullptr);
+ /**
+ * \brief Creates a new FileManifest with the specified values
+ *
+ * @param name The Name of this FileManifest
+ * @param dataPacketSize The size (except the last) of each data packet in this FileManifest
+ * @param commonPrefix The common prefix used for all named in the catalog
+ * @param catalog The collection of Names for this FileManifest
+ * @param subManifestPtr (optional) The Name for the sub-manifest in this for this file
+ */
+
+ FileManifest(const Name& name,
+ size_t dataPacketSize,
+ const Name& catalogPrefix,
+ std::vector<Name>&& catalog,
+ std::shared_ptr<Name> subManifestPtr = nullptr);
+ /**
+ * \brief Creates a new FileManifest with the specified values
+ *
+ * @param name The Name of this FileManifest
+ * @param dataPacketSize The size (except the last) of each data packet in this FileManifest
+ * @param catalogPrefix the common prefix used for all named in the catalog
+ * @param catalog The collection of Names for this FileManifest
+ * @param subManifestPtr (optional) The Name for the sub-manifest in this for this file
+ */
+
+ explicit
+ FileManifest(const Block& block);
+
+ FileManifest(const FileManifest& other) = default;
+ /// Creates a new FileManifest with same value as the specified 'other'
+
+ // ACCESSORS
+ const Name&
+ name() const;
+ /// Returns the 'name' of this FileManifest
+
+ const Name&
+ catalog_prefix() const;
+ /// Returns the 'catalogPrefix' of this FileManfiest.
+
+ size_t
+ data_packet_size() const;
+ /// Returns the 'data_packet_size' of this FileManifest
+
+ std::shared_ptr<Name>
+ submanifest_ptr() const;
+ /// Returns the 'submanifest_ptr' of this FileManifest, or 'nullptr' is none exists
+
+ const std::vector<Name>&
+ catalog() const;
+ /// Returns an unmodifiable reference to the 'catalog' of this FileManifest
+
+ private:
+ template<encoding::Tag TAG>
+ size_t
+ encodeContent(EncodingImpl<TAG>& encoder) const;
+ /// Encodes the contents of this object and append the contents to the 'encoder'
+
+ public:
+ // MANIPULATORS
+ FileManifest&
+ operator=(const FileManifest& rhs) = default;
+ /// Assigns the value of the specific 'rhs' object to this object.
+
+ void
+ push_back(const Name& name);
+ /// Appends a Name to the catalog
+
+ bool
+ remove(const Name& name);
+ /// If 'name' in catalog, removes first instance and returns 'true', otherwise returns 'false'.
+
+ void
+ wireDecode(const Block& wire);
+ /**
+ * \brief Decodes the wire and assign its contents to this FileManifest
+ *
+ * @param wire the write to be decoded
+ * @throws Error if decoding fails
+ */
+ const Block&
+ wireEncode();
+ /// Encodes this FileManifest into the wire format and returns a Block with the contents
+
+private:
+ void
+ decodeContent();
+ /// Decodes the contents of this Data packet, assigning its contents to this FileManifest.
+
+ void
+ encodeContent();
+ /// Encodes the contents of this FileManifest into the content section of its Data packet.
+
+// DATA
+ private:
+ size_t m_dataPacketSize;
+ Name m_catalogPrefix;
+ std::vector<Name> m_catalog;
+ std::shared_ptr<Name> m_submanifestPtr;
+};
+
+/// Non-member functions
+bool operator==(const FileManifest& lhs, const FileManifest& rhs);
+/// Returns 'true' if 'lhs' and 'rhs' have the same value, 'false' otherwise.
+
+bool operator!=(const FileManifest& lhs, const FileManifest& rhs);
+/// Returns 'true' if 'lhs' and 'rhs' have different values, and 'false' otherwise.
+
+inline
+FileManifest::FileManifest(
+ const Name& name,
+ size_t dataPacketSize,
+ const Name& catalogPrefix,
+ const std::vector<Name>& catalog,
+ std::shared_ptr<Name> subManifestPtr)
+: Data(name)
+, m_dataPacketSize(dataPacketSize)
+, m_catalogPrefix(catalogPrefix)
+, m_catalog(catalog)
+, m_submanifestPtr(subManifestPtr)
+{
+}
+
+inline
+FileManifest::FileManifest(
+ const Name& name,
+ size_t dataPacketSize,
+ const Name& catalogPrefix,
+ std::vector<Name>&& catalog,
+ std::shared_ptr<Name> subManifestPtr)
+: Data(name)
+, m_dataPacketSize(dataPacketSize)
+, m_catalogPrefix(catalogPrefix)
+, m_catalog(catalog)
+, m_submanifestPtr(subManifestPtr)
+{
+}
+
+inline
+FileManifest::FileManifest(const Block& block)
+{
+ wireDecode(block);
+}
+
+inline const Name&
+FileManifest::name() const
+{
+ return getName();
+}
+
+inline size_t
+FileManifest::data_packet_size() const
+{
+ return m_dataPacketSize;
+}
+
+inline const Name&
+FileManifest::catalog_prefix() const
+{
+ return m_catalogPrefix;
+}
+
+inline const std::vector<Name>&
+FileManifest::catalog() const
+{
+ return m_catalog;
+}
+
+inline std::shared_ptr<Name>
+FileManifest::submanifest_ptr() const
+{
+ return m_submanifestPtr;
+}
+
+} // end ntorrent
+} // end ndn
+
+#endif // INCLUDED_FILE_MANIFEST_HPP