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