blob: bf53c86388a19b37230071fb4313d209185adfcc [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013-2023 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
* ndn-cxx library 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.
*
* ndn-cxx library 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 ndn-cxx, e.g., in COPYING.md file. If not, see
* <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*/
#include "ndn-cxx/encoding/block-helpers.hpp"
#include <boost/endian/conversion.hpp>
namespace ndn::encoding {
namespace endian = boost::endian;
// ---- empty ----
template<Tag TAG>
size_t
prependEmptyBlock(EncodingImpl<TAG>& encoder, uint32_t type)
{
size_t length = encoder.prependVarNumber(0);
length += encoder.prependVarNumber(type);
return length;
}
template size_t
prependEmptyBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, uint32_t);
template size_t
prependEmptyBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t);
Block
makeEmptyBlock(uint32_t type)
{
EncodingEstimator estimator;
size_t totalLength = prependEmptyBlock(estimator, type);
EncodingBuffer encoder(totalLength, 0);
prependEmptyBlock(encoder, type);
return encoder.block();
}
// ---- non-negative integer ----
template<Tag TAG>
size_t
prependNonNegativeIntegerBlock(EncodingImpl<TAG>& encoder, uint32_t type, uint64_t value)
{
size_t length = encoder.prependNonNegativeInteger(value);
length += encoder.prependVarNumber(length);
length += encoder.prependVarNumber(type);
return length;
}
template size_t
prependNonNegativeIntegerBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, uint32_t, uint64_t);
template size_t
prependNonNegativeIntegerBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t, uint64_t);
Block
makeNonNegativeIntegerBlock(uint32_t type, uint64_t value)
{
EncodingEstimator estimator;
size_t totalLength = prependNonNegativeIntegerBlock(estimator, type, value);
EncodingBuffer encoder(totalLength, 0);
prependNonNegativeIntegerBlock(encoder, type, value);
return encoder.block();
}
uint64_t
readNonNegativeInteger(const Block& block)
{
auto begin = block.value_begin();
return tlv::readNonNegativeInteger(block.value_size(), begin, block.value_end());
}
// ---- double ----
static_assert(std::numeric_limits<double>::is_iec559, "This code requires IEEE-754 doubles");
template<Tag TAG>
size_t
prependDoubleBlock(EncodingImpl<TAG>& encoder, uint32_t type, double value)
{
uint64_t temp = 0;
std::memcpy(&temp, &value, 8);
endian::native_to_big_inplace(temp);
return prependBinaryBlock(encoder, type, {reinterpret_cast<const uint8_t*>(&temp), 8});
}
template size_t
prependDoubleBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, uint32_t, double);
template size_t
prependDoubleBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t, double);
Block
makeDoubleBlock(uint32_t type, double value)
{
EncodingEstimator estimator;
size_t totalLength = prependDoubleBlock(estimator, type, value);
EncodingBuffer encoder(totalLength, 0);
prependDoubleBlock(encoder, type, value);
return encoder.block();
}
double
readDouble(const Block& block)
{
if (block.value_size() != 8) {
NDN_THROW(tlv::Error("Invalid length for double (must be 8)"));
}
#if BOOST_VERSION >= 107100
return endian::endian_load<double, 8, endian::order::big>(block.value());
#else
uint64_t temp = 0;
std::memcpy(&temp, block.value(), 8);
endian::big_to_native_inplace(temp);
double d = 0;
std::memcpy(&d, &temp, 8);
return d;
#endif
}
// ---- binary ----
template<Tag TAG>
size_t
prependBinaryBlock(EncodingImpl<TAG>& encoder, uint32_t type, span<const uint8_t> value)
{
size_t length = encoder.prependBytes(value);
length += encoder.prependVarNumber(length);
length += encoder.prependVarNumber(type);
return length;
}
template size_t
prependBinaryBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, uint32_t, span<const uint8_t>);
template size_t
prependBinaryBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t, span<const uint8_t>);
Block
makeBinaryBlock(uint32_t type, span<const uint8_t> value)
{
EncodingEstimator estimator;
size_t totalLength = prependBinaryBlock(estimator, type, value);
EncodingBuffer encoder(totalLength, 0);
prependBinaryBlock(encoder, type, value);
return encoder.block();
}
// ---- string ----
template<Tag TAG>
size_t
prependStringBlock(EncodingImpl<TAG>& encoder, uint32_t type, std::string_view value)
{
return prependBinaryBlock(encoder, type, {reinterpret_cast<const uint8_t*>(value.data()), value.size()});
}
template size_t
prependStringBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, uint32_t, std::string_view);
template size_t
prependStringBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t, std::string_view);
std::string
readString(const Block& block)
{
return std::string(reinterpret_cast<const char*>(block.value()), block.value_size());
}
// ---- block ----
template<Tag TAG>
size_t
prependBlock(EncodingImpl<TAG>& encoder, const Block& block)
{
if (block.hasWire()) {
return encoder.prependBytes(block);
}
else {
// FIXME: blindly calling Block::value_bytes() is not safe if the value is not wire-encoded
return prependBinaryBlock(encoder, block.type(), block.value_bytes());
}
}
template size_t
prependBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, const Block&);
template size_t
prependBlock<EncoderTag>(EncodingImpl<EncoderTag>&, const Block&);
} // namespace ndn::encoding