ndnsec: improve error reporting when loading a Certificate or SafeBag fails
Refs: #5164
Change-Id: I6f594a921bb063ad808f311d8ff978bf0f7d528d
diff --git a/ndn-cxx/util/io.cpp b/ndn-cxx/util/io.cpp
index a385eea..0fff144 100644
--- a/ndn-cxx/util/io.cpp
+++ b/ndn-cxx/util/io.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2021 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -52,27 +52,13 @@
return os.buf();
}
}
- catch (const t::Error& e) {
+ catch (const std::runtime_error& e) {
NDN_THROW_NESTED(Error(e.what()));
}
NDN_THROW(std::invalid_argument("Unknown IoEncoding " + to_string(encoding)));
}
-optional<Block>
-loadBlock(std::istream& is, IoEncoding encoding)
-{
- try {
- return make_optional<Block>(loadBuffer(is, encoding));
- }
- catch (const std::invalid_argument&) {
- return nullopt;
- }
- catch (const std::runtime_error&) {
- return nullopt;
- }
-}
-
void
saveBuffer(const uint8_t* buf, size_t size, std::ostream& os, IoEncoding encoding)
{
@@ -91,18 +77,12 @@
return;
}
}
- catch (const t::Error& e) {
+ catch (const std::runtime_error& e) {
NDN_THROW_NESTED(Error(e.what()));
}
NDN_THROW(std::invalid_argument("Unknown IoEncoding " + to_string(encoding)));
}
-void
-saveBlock(const Block& block, std::ostream& os, IoEncoding encoding)
-{
- saveBuffer(block.wire(), block.size(), os, encoding);
-}
-
} // namespace io
} // namespace ndn
diff --git a/ndn-cxx/util/io.hpp b/ndn-cxx/util/io.hpp
index 99b798d..7a2afd6 100644
--- a/ndn-cxx/util/io.hpp
+++ b/ndn-cxx/util/io.hpp
@@ -62,7 +62,7 @@
template<typename T>
static void
-checkInnerError(typename T::Error*)
+checkNestedError(typename T::Error*)
{
static_assert(std::is_convertible<typename T::Error*, tlv::Error*>::value,
"T::Error, if defined, must be a subclass of ndn::tlv::Error");
@@ -70,56 +70,83 @@
template<typename T>
static void
-checkInnerError(...)
+checkNestedError(...)
{
// T::Error is not defined
}
} // namespace detail
-/** \brief Reads bytes from a stream until EOF.
- * \return a Buffer containing the bytes read from the stream
- * \throw Error error during loading
- * \throw std::invalid_argument the specified encoding is not supported
+/**
+ * \brief Reads bytes from a stream until EOF.
+ * \return a Buffer containing the bytes read from the stream
+ * \throw Error An error occurred, e.g., malformed input.
+ * \throw std::invalid_argument The specified encoding is not supported.
*/
shared_ptr<Buffer>
loadBuffer(std::istream& is, IoEncoding encoding = BASE64);
-/** \brief Reads a TLV block from a stream.
- * \return a Block, or nullopt if an error occurs
+/**
+ * \brief Reads a TLV element of type `T` from a stream.
+ * \tparam T Class type representing the TLV element; must be WireDecodable.
+ * \return the parsed TLV element
+ * \throw Error An error occurred, e.g., malformed input.
+ * \throw std::invalid_argument The specified encoding is not supported.
*/
-optional<Block>
-loadBlock(std::istream& is, IoEncoding encoding = BASE64);
+template<typename T>
+T
+loadTlv(std::istream& is, IoEncoding encoding = BASE64)
+{
+ BOOST_CONCEPT_ASSERT((WireDecodable<T>));
-/** \brief Reads a TLV element from a stream.
- * \tparam T type of TLV element; `T` must be WireDecodable and the nested type
- * `T::Error`, if defined, must be a subclass of ndn::tlv::Error
- * \return the TLV element, or nullptr if an error occurs
+ auto buf = loadBuffer(is, encoding);
+ try {
+ return T(Block(buf));
+ }
+ catch (const std::exception& e) {
+ NDN_THROW_NESTED(Error("Decode error during load: "s + e.what()));
+ }
+}
+
+/**
+ * \brief Reads a TLV element from a stream.
+ * \tparam T Type of TLV element; `T` must be WireDecodable and the nested type
+ * `T::Error`, if defined, must be a subclass of ndn::tlv::Error.
+ * \return the TLV element, or nullptr if an error occurs
+ * \note This function has a peculiar error handling behavior. Consider using loadTlv() instead.
*/
template<typename T>
shared_ptr<T>
load(std::istream& is, IoEncoding encoding = BASE64)
{
BOOST_CONCEPT_ASSERT((WireDecodable<T>));
- detail::checkInnerError<T>(nullptr);
+ detail::checkNestedError<T>(nullptr);
- auto block = loadBlock(is, encoding);
- if (!block) {
+ Block block;
+ try {
+ block = Block(loadBuffer(is, encoding));
+ }
+ catch (const std::invalid_argument&) {
+ return nullptr;
+ }
+ catch (const std::runtime_error&) {
return nullptr;
}
try {
- return make_shared<T>(*block);
+ return make_shared<T>(block);
}
catch (const tlv::Error&) {
return nullptr;
}
}
-/** \brief Reads a TLV element from a file.
- * \tparam T type of TLV element; `T` must be WireDecodable and the nested type
- * `T::Error`, if defined, must be a subclass of ndn::tlv::Error
- * \return the TLV element, or nullptr if an error occurs
+/**
+ * \brief Reads a TLV element from a file.
+ * \tparam T Type of TLV element; `T` must be WireDecodable and the nested type
+ * `T::Error`, if defined, must be a subclass of ndn::tlv::Error.
+ * \return the TLV element, or nullptr if an error occurs
+ * \note This function has a peculiar error handling behavior. Consider using loadTlv() instead.
*/
template<typename T>
shared_ptr<T>
@@ -136,13 +163,6 @@
void
saveBuffer(const uint8_t* buf, size_t size, std::ostream& os, IoEncoding encoding = BASE64);
-/** \brief Writes a TLV block to a stream.
- * \throw Error error during saving
- * \throw std::invalid_argument the specified encoding is not supported
- */
-void
-saveBlock(const Block& block, std::ostream& os, IoEncoding encoding = BASE64);
-
/** \brief Writes a TLV element to a stream.
* \tparam T type of TLV element; `T` must be WireEncodable and the nested type
* `T::Error`, if defined, must be a subclass of ndn::tlv::Error
@@ -154,17 +174,17 @@
save(const T& obj, std::ostream& os, IoEncoding encoding = BASE64)
{
BOOST_CONCEPT_ASSERT((WireEncodable<T>));
- detail::checkInnerError<T>(nullptr);
+ detail::checkNestedError<T>(nullptr);
Block block;
try {
block = obj.wireEncode();
}
- catch (const tlv::Error&) {
- NDN_THROW_NESTED(Error("Encode error during save"));
+ catch (const tlv::Error& e) {
+ NDN_THROW_NESTED(Error("Encode error during save: "s + e.what()));
}
- saveBlock(block, os, encoding);
+ saveBuffer(block.wire(), block.size(), os, encoding);
}
/** \brief Writes a TLV element to a file.
diff --git a/tests/unit/util/io.t.cpp b/tests/unit/util/io.t.cpp
index 1ebaf61..8b19fe3 100644
--- a/tests/unit/util/io.t.cpp
+++ b/tests/unit/util/io.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2020 Regents of the University of California.
+ * Copyright (c) 2013-2021 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -92,6 +92,7 @@
BOOST_AUTO_TEST_CASE(UnknownIoEncoding)
{
std::stringstream ss;
+ BOOST_CHECK_THROW(io::loadTlv<Name>(ss, static_cast<io::IoEncoding>(5)), std::invalid_argument);
BOOST_CHECK_THROW(io::loadBuffer(ss, static_cast<io::IoEncoding>(5)), std::invalid_argument);
BOOST_CHECK_THROW(io::saveBuffer(nullptr, 0, ss, static_cast<io::IoEncoding>(5)), std::invalid_argument);
}
@@ -112,7 +113,8 @@
boost::filesystem::remove(filepath, ec); // ignore error
}
- /** \brief create a directory at filename, so that it's neither readable nor writable as a file
+ /**
+ * \brief create a directory at `filepath`, so that it's neither readable nor writable as a file
*/
void
mkdir() const
@@ -171,25 +173,20 @@
bool shouldThrow = false;
};
-template<bool SHOULD_THROW>
-class DecodableTypeTpl
+class DecodableType
{
public:
- DecodableTypeTpl() = default;
+ DecodableType() = default;
explicit
- DecodableTypeTpl(const Block& block)
+ DecodableType(const Block& block)
{
- this->wireDecode(block);
+ wireDecode(block);
}
void
wireDecode(const Block& block)
{
- if (SHOULD_THROW) {
- NDN_THROW(tlv::Error("decode error"));
- }
-
// block must be 0xBB, 0x01, 0xEE
BOOST_CHECK_EQUAL(block.type(), 0xBB);
BOOST_REQUIRE_EQUAL(block.value_size(), 1);
@@ -197,14 +194,32 @@
}
};
-using DecodableType = DecodableTypeTpl<false>;
-using DecodableTypeThrow = DecodableTypeTpl<true>;
+class DecodableTypeThrow
+{
+public:
+ DecodableTypeThrow() = default;
+
+ explicit
+ DecodableTypeThrow(const Block& block)
+ {
+ wireDecode(block);
+ }
+
+ void
+ wireDecode(const Block&)
+ {
+ NDN_THROW(tlv::Error("decode error"));
+ }
+};
BOOST_AUTO_TEST_CASE(LoadNoEncoding)
{
this->writeFile<std::vector<uint8_t>>({0xBB, 0x01, 0xEE});
shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::NO_ENCODING);
BOOST_CHECK(decoded != nullptr);
+
+ std::ifstream ifs(filename);
+ BOOST_CHECK_NO_THROW(io::loadTlv<DecodableType>(ifs, io::NO_ENCODING));
}
BOOST_AUTO_TEST_CASE(LoadBase64)
@@ -212,6 +227,9 @@
this->writeFile<std::string>("uwHu\n"); // printf '\xBB\x01\xEE' | base64
shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::BASE64);
BOOST_CHECK(decoded != nullptr);
+
+ std::ifstream ifs(filename);
+ BOOST_CHECK_NO_THROW(io::loadTlv<DecodableType>(ifs, io::BASE64));
}
BOOST_AUTO_TEST_CASE(LoadBase64Newline64)
@@ -225,6 +243,9 @@
// \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | base64
shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
BOOST_CHECK(decoded != nullptr);
+
+ std::ifstream ifs(filename);
+ BOOST_CHECK_NO_THROW(io::loadTlv<name::Component>(ifs, io::BASE64));
}
BOOST_AUTO_TEST_CASE(LoadBase64Newline32)
@@ -235,6 +256,9 @@
"AAAAAAAAAAAA\n");
shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
BOOST_CHECK(decoded != nullptr);
+
+ std::ifstream ifs(filename);
+ BOOST_CHECK_NO_THROW(io::loadTlv<name::Component>(ifs, io::BASE64));
}
BOOST_AUTO_TEST_CASE(LoadBase64NewlineEnd)
@@ -243,6 +267,9 @@
"CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n");
shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
BOOST_CHECK(decoded != nullptr);
+
+ std::ifstream ifs(filename);
+ BOOST_CHECK_NO_THROW(io::loadTlv<name::Component>(ifs, io::BASE64));
}
BOOST_AUTO_TEST_CASE(LoadBase64NoNewline)
@@ -251,6 +278,9 @@
"CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
BOOST_CHECK(decoded != nullptr);
+
+ std::ifstream ifs(filename);
+ BOOST_CHECK_NO_THROW(io::loadTlv<name::Component>(ifs, io::BASE64));
}
BOOST_AUTO_TEST_CASE(LoadHex)
@@ -258,14 +288,20 @@
this->writeFile<std::string>("BB01EE");
shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::HEX);
BOOST_CHECK(decoded != nullptr);
+
+ std::ifstream ifs(filename);
+ BOOST_CHECK_NO_THROW(io::loadTlv<DecodableType>(ifs, io::HEX));
}
-BOOST_AUTO_TEST_CASE(LoadException)
+BOOST_AUTO_TEST_CASE(LoadDecodeException)
{
this->writeFile<std::vector<uint8_t>>({0xBB, 0x01, 0xEE});
shared_ptr<DecodableTypeThrow> decoded;
BOOST_CHECK_NO_THROW(decoded = io::load<DecodableTypeThrow>(filename, io::NO_ENCODING));
BOOST_CHECK(decoded == nullptr);
+
+ std::ifstream ifs(filename);
+ BOOST_CHECK_THROW(io::loadTlv<DecodableTypeThrow>(ifs, io::NO_ENCODING), io::Error);
}
BOOST_AUTO_TEST_CASE(LoadNotHex)
@@ -274,6 +310,20 @@
shared_ptr<DecodableType> decoded;
BOOST_CHECK_NO_THROW(decoded = io::load<DecodableType>(filename, io::HEX));
BOOST_CHECK(decoded == nullptr);
+
+ std::ifstream ifs(filename);
+ BOOST_CHECK_THROW(io::loadTlv<DecodableType>(ifs, io::HEX), io::Error);
+}
+
+BOOST_AUTO_TEST_CASE(LoadEmpty)
+{
+ this->writeFile<std::vector<uint8_t>>({});
+ shared_ptr<DecodableType> decoded;
+ BOOST_CHECK_NO_THROW(decoded = io::load<DecodableType>(filename, io::NO_ENCODING));
+ BOOST_CHECK(decoded == nullptr);
+
+ std::ifstream ifs(filename);
+ BOOST_CHECK_THROW(io::loadTlv<DecodableType>(ifs, io::NO_ENCODING), io::Error);
}
BOOST_AUTO_TEST_CASE(LoadFileNotReadable)
diff --git a/tools/ndnsec/cert-dump.cpp b/tools/ndnsec/cert-dump.cpp
index 5a388d7..9f86f1c 100644
--- a/tools/ndnsec/cert-dump.cpp
+++ b/tools/ndnsec/cert-dump.cpp
@@ -22,8 +22,6 @@
#include "ndnsec.hpp"
#include "util.hpp"
-#include "ndn-cxx/util/io.hpp"
-
#include <boost/asio/ip/tcp.hpp>
#if BOOST_VERSION < 106700
#include <boost/date_time/posix_time/posix_time_duration.hpp>
@@ -109,13 +107,7 @@
security::Certificate certificate;
if (isFileName) {
- try {
- certificate = loadCertificate(name);
- }
- catch (const CannotLoadCertificate&) {
- std::cerr << "ERROR: Cannot load the certificate from `" << name << "`" << std::endl;
- return 1;
- }
+ certificate = loadFromFile<security::Certificate>(name);
}
else {
KeyChain keyChain;
diff --git a/tools/ndnsec/cert-gen.cpp b/tools/ndnsec/cert-gen.cpp
index 9c11ca4..8772062 100644
--- a/tools/ndnsec/cert-gen.cpp
+++ b/tools/ndnsec/cert-gen.cpp
@@ -124,14 +124,7 @@
KeyChain keyChain;
- security::Certificate certRequest;
- try {
- certRequest = loadCertificate(requestFile);
- }
- catch (const CannotLoadCertificate&) {
- std::cerr << "ERROR: Cannot load the request from `" << requestFile << "`" << std::endl;
- return 1;
- }
+ auto certRequest = loadFromFile<security::Certificate>(requestFile);
// validate that the content is a public key
Buffer keyContent = certRequest.getPublicKey();
@@ -165,9 +158,9 @@
keyChain.sign(cert, security::SigningInfo(identity).setSignatureInfo(signatureInfo));
- const Block& wire = cert.wireEncode();
{
using namespace security::transform;
+ const auto& wire = cert.wireEncode();
bufferSource(wire.wire(), wire.size()) >> base64Encode(true) >> streamSink(std::cout);
}
diff --git a/tools/ndnsec/cert-install.cpp b/tools/ndnsec/cert-install.cpp
index 7a6afa2..caa10b6 100644
--- a/tools/ndnsec/cert-install.cpp
+++ b/tools/ndnsec/cert-install.cpp
@@ -159,8 +159,8 @@
}
security::Certificate cert;
- try {
- if (certFile.find("http://") == 0) {
+ if (certFile.find("http://") == 0) {
+ try {
std::string host;
std::string port;
std::string path;
@@ -172,7 +172,6 @@
NDN_THROW(HttpException("Request line is not correctly formatted"));
size_t posPort = certFile.find(':', pos);
-
if (posPort != std::string::npos && posPort < posSlash) {
// port is specified
port = certFile.substr(posPort + 1, posSlash - posPort - 1);
@@ -187,13 +186,14 @@
cert = getCertificateHttp(host, port, path);
}
- else {
- cert = loadCertificate(certFile);
+ catch (const std::runtime_error& e) {
+ std::cerr << "ERROR: Cannot download the certificate from '" << certFile
+ << "': " << e.what() << std::endl;
+ return 1;
}
}
- catch (const CannotLoadCertificate&) {
- std::cerr << "ERROR: Cannot load the certificate from `" << certFile << "`" << std::endl;
- return 1;
+ else {
+ cert = loadFromFile<security::Certificate>(certFile);
}
KeyChain keyChain;
diff --git a/tools/ndnsec/export.cpp b/tools/ndnsec/export.cpp
index f0a9395..f11cc96 100644
--- a/tools/ndnsec/export.cpp
+++ b/tools/ndnsec/export.cpp
@@ -23,7 +23,6 @@
#include "util.hpp"
#include "ndn-cxx/security/impl/openssl.hpp"
-#include "ndn-cxx/util/io.hpp"
#include "ndn-cxx/util/scope.hpp"
namespace ndn {
diff --git a/tools/ndnsec/import.cpp b/tools/ndnsec/import.cpp
index 7e27bee..2fb6755 100644
--- a/tools/ndnsec/import.cpp
+++ b/tools/ndnsec/import.cpp
@@ -23,7 +23,6 @@
#include "util.hpp"
#include "ndn-cxx/security/impl/openssl.hpp"
-#include "ndn-cxx/util/io.hpp"
#include "ndn-cxx/util/scope.hpp"
namespace ndn {
@@ -74,11 +73,7 @@
KeyChain keyChain;
- shared_ptr<security::SafeBag> safeBag;
- if (input == "-")
- safeBag = io::load<security::SafeBag>(std::cin);
- else
- safeBag = io::load<security::SafeBag>(input);
+ auto safeBag = loadFromFile<security::SafeBag>(input);
if (password.empty()) {
int count = 3;
@@ -91,7 +86,7 @@
}
}
- keyChain.importSafeBag(*safeBag, password.data(), password.size());
+ keyChain.importSafeBag(safeBag, password.data(), password.size());
return 0;
}
diff --git a/tools/ndnsec/key-gen.cpp b/tools/ndnsec/key-gen.cpp
index 2090f74..6773e72 100644
--- a/tools/ndnsec/key-gen.cpp
+++ b/tools/ndnsec/key-gen.cpp
@@ -22,8 +22,6 @@
#include "ndnsec.hpp"
#include "util.hpp"
-#include "ndn-cxx/util/io.hpp"
-
namespace ndn {
namespace ndnsec {
diff --git a/tools/ndnsec/main.cpp b/tools/ndnsec/main.cpp
index 024e5d5..e731b5c 100644
--- a/tools/ndnsec/main.cpp
+++ b/tools/ndnsec/main.cpp
@@ -22,6 +22,7 @@
#include "ndnsec.hpp"
#include "ndn-cxx/util/logger.hpp"
+#include "ndn-cxx/util/logging.hpp"
#include "ndn-cxx/version.hpp"
#include <boost/exception/diagnostic_information.hpp>
@@ -111,6 +112,7 @@
catch (const std::exception& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
NDN_LOG_ERROR(boost::diagnostic_information(e));
+ ndn::util::Logging::flush();
return 1;
}
diff --git a/tools/ndnsec/ndnsec-pch.hpp b/tools/ndnsec/ndnsec-pch.hpp
index c72b650..c059d36 100644
--- a/tools/ndnsec/ndnsec-pch.hpp
+++ b/tools/ndnsec/ndnsec-pch.hpp
@@ -24,8 +24,6 @@
#include "util.hpp"
-#include "ndn-cxx/util/io.hpp"
-
#include <boost/asio/ip/tcp.hpp>
#endif // NDN_CXX_TOOLS_NDNSEC_NDNSEC_PCH_HPP
diff --git a/tools/ndnsec/sign-req.cpp b/tools/ndnsec/sign-req.cpp
index 3548228..6151714 100644
--- a/tools/ndnsec/sign-req.cpp
+++ b/tools/ndnsec/sign-req.cpp
@@ -22,8 +22,6 @@
#include "ndnsec.hpp"
#include "util.hpp"
-#include "ndn-cxx/util/io.hpp"
-
namespace ndn {
namespace ndnsec {
diff --git a/tools/ndnsec/util.cpp b/tools/ndnsec/util.cpp
index 0ff7e74..d79df47 100644
--- a/tools/ndnsec/util.cpp
+++ b/tools/ndnsec/util.cpp
@@ -22,7 +22,6 @@
#include "util.hpp"
#include "ndn-cxx/security/impl/openssl.hpp"
-#include "ndn-cxx/util/io.hpp"
#include <unistd.h>
@@ -90,20 +89,5 @@
NDN_CXX_UNREACHABLE;
}
-security::Certificate
-loadCertificate(const std::string& fileName)
-{
- shared_ptr<security::Certificate> cert;
- if (fileName == "-")
- cert = io::load<security::Certificate>(std::cin);
- else
- cert = io::load<security::Certificate>(fileName);
-
- if (cert == nullptr) {
- NDN_THROW(CannotLoadCertificate(fileName));
- }
- return *cert;
-}
-
} // namespace ndnsec
} // namespace ndn
diff --git a/tools/ndnsec/util.hpp b/tools/ndnsec/util.hpp
index 4ce3c04..913198c 100644
--- a/tools/ndnsec/util.hpp
+++ b/tools/ndnsec/util.hpp
@@ -23,6 +23,7 @@
#define NDN_CXX_TOOLS_NDNSEC_UTIL_HPP
#include "ndn-cxx/security/key-chain.hpp"
+#include "ndn-cxx/util/io.hpp"
#include <iostream>
@@ -49,17 +50,29 @@
getCertificateFromPib(const security::pib::Pib& pib, const Name& name,
bool isIdentityName, bool isKeyName, bool isCertName);
-class CannotLoadCertificate : public std::runtime_error
+/**
+ * @brief Load a TLV-encoded, base64-armored object from a file named @p filename.
+ */
+template<typename T>
+T
+loadFromFile(const std::string& filename)
{
-public:
- CannotLoadCertificate(const std::string& msg)
- : std::runtime_error(msg)
- {
- }
-};
+ try {
+ if (filename == "-") {
+ return io::loadTlv<T>(std::cin, io::BASE64);
+ }
-security::Certificate
-loadCertificate(const std::string& fileName);
+ std::ifstream file(filename);
+ if (!file) {
+ NDN_THROW(std::runtime_error("Cannot open '" + filename + "'"));
+ }
+ return io::loadTlv<T>(file, io::BASE64);
+ }
+ catch (const io::Error& e) {
+ NDN_THROW_NESTED(std::runtime_error("Cannot load '" + filename +
+ "': malformed TLV or not in base64 format (" + e.what() + ")"));
+ }
+}
bool
getPassword(std::string& password, const std::string& prompt, bool shouldConfirm = true);
diff --git a/wscript b/wscript
index 966268c..67cd3a9 100644
--- a/wscript
+++ b/wscript
@@ -80,7 +80,6 @@
conf.env.WITH_TOOLS = conf.options.with_tools
conf.env.WITH_EXAMPLES = conf.options.with_examples
- conf.find_program('sh', var='SH')
conf.find_program('dot', var='DOT', mandatory=False)
conf.check_cxx(lib='atomic', uselib_store='ATOMIC', define_name='HAVE_ATOMIC', mandatory=False)