1
0
Fork 0

use the bufferstream library

This commit is contained in:
Kevin Matz 2023-04-02 13:24:55 -04:00
parent 1ea49ebde2
commit 8e41fc72c2
25 changed files with 59 additions and 499 deletions

View File

@ -253,7 +253,7 @@ void QSacnNode::udpReceive()
// wrap a PDU i/o stream around the QNetworkDatagram data buffer
auto data = datagram.data();
auto stream = std::make_shared<ACN::PDU::pdu_stream>(
auto stream = std::make_shared<bufferstream>(
reinterpret_cast<uint8_t*>(data.data()), data.length());
UdpPayloadReceiver(stream);
}

View File

@ -34,6 +34,7 @@ target_sources(${PROJECT_NAME}-pdu
target_link_libraries(${PROJECT_NAME}-pdu
PUBLIC
LCP::BufferStream
LCP::UUID
)

View File

@ -82,7 +82,7 @@ struct address_type
*/
/// \todo maybe template this struct based on address_length
struct Range
: PDU::pdu_stream_object
: streamable
{
/**
* @brief range constructor

View File

@ -21,370 +21,36 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "pdu-stream.h"
namespace ACN {
namespace PDU {
/**
* @brief pdu_stream::pdu_stream
* @param p the packet buffer
* @param l buffer length
*/
pdu_stream::pdu_stream(uint8_t * p, std::streamsize l)
: std::basic_streambuf<uint8_t>()
, std::basic_iostream<uint8_t>(this)
{
setg(p, p, p + l);
setp(p, p + l);
}
/**
* @brief pdu_stream::available
* @return
*/
uint32_t pdu_stream::available()
{
return in_avail();
}
/**
* @brief pdu_stream::data
* @return
*/
uint8_t * pdu_stream::data()
{
return gptr();
}
/**
* @brief pdu_stream::size
* @return
*/
uint32_t pdu_stream::size()
{
return pptr() - pbase();
}
/**
* @brief pdu_stream::base
* @return
*/
uint8_t * pdu_stream::base()
{
return pbase();
}
/**
* @brief pdu_stream::readString
* @param str std::string to which the read string will be appended.
* @param fixed_length this many bytes will be read from the stream. If 0, all
* available bytes on the stream will be used to construct the appended string.
*/
void pdu_stream::readString(std::string &str, const int fixed_length)
{
// if fixed_length == 0, use all available data on the stream
if (!fixed_length)
{
str += std::string(reinterpret_cast<char*>(data()), available());
return setstate(std::ios_base::eofbit);
}
// otherwise, construct a buffer and read into that.
uint8_t buffer[fixed_length];
read(buffer, fixed_length);
if (gcount() != fixed_length)
return setstate(std::ios_base::failbit);
str += std::string(reinterpret_cast<char*>(buffer));
}
/**
* @brief pdu_stream::writeString
* @param str
* @param fixed_length write this length to the stream, padding with null
* if str is shorter than fixed_length. If 0, will write the unrestricted
* contents of str.
* @param terminated If true, the last byte of fixed_length is guaranteed to
* be a 0 (null) byte.
*/
void pdu_stream::writeString(const std::string &str, const size_t fixed_length,
const bool terminated)
{
// fixed_length == 0 means dynamic length.
bool fixed = fixed_length > 0 ? true : false;
// fixed length strings restricted to fixed_lengh characters
size_t maxlen = fixed ? fixed_length : str.size();
// write no more of the string than is available
size_t wrtlen = str.size() < maxlen ? str.size() : maxlen;
// terminated fixed-length strings get a guaranteed padding byte
if (fixed && terminated && wrtlen == maxlen)
--wrtlen;
// output the correct ammount of data from the string
write(reinterpret_cast<const uint8_t*>(str.data()), wrtlen);
// output any required padding bytes
for (size_t i = wrtlen; i < maxlen; i++)
put(0);
}
/**
* @brief pdu_stream::operator >>
* @param obj
* @return
*/
pdu_stream& pdu_stream::operator>> (pdu_stream_object& obj)
{
obj.iStream(shared_from_this());
return *this;
}
/**
* @brief pdu_stream::operator >>
* @param val
* @return
*/
pdu_stream& pdu_stream::operator>> (uint8_t& val)
{
val = readType<uint8_t>();
return *this;
};
/**
* @brief pdu_stream::operator >>
* @param val
* @return
*/
pdu_stream& pdu_stream::operator>> (uint16_t& val)
{
val = readType<uint16_t>();
return *this;
};
/**
* @brief pdu_stream::operator >>
* @param val
* @return
*/
pdu_stream& pdu_stream::operator>> (uint32_t& val)
{
val = readType<uint32_t>();
return *this;
};
/**
* @brief pdu_stream::operator >>
* @param val
* @return
*/
pdu_stream& pdu_stream::operator>> (uint64_t& val)
{
val = readType<uint64_t>();
return *this;
};
/**
* @brief pdu_stream::operator >>
* @param val
* @return
*/
pdu_stream& pdu_stream::operator>> (int8_t& val)
{
val = readType<int8_t>();
return *this;
}
/**
* @brief pdu_stream::operator <<
* @param val
* @return
*/
pdu_stream& pdu_stream::operator<< (const int8_t& val)
{
put(val);
return *this;
}
/**
* @brief pdu_stream::operator >>
* @param val
* @return
*/
pdu_stream& pdu_stream::operator>> (int16_t& val)
{
val = readType<int16_t>();
return *this;
}
/**
* @brief pdu_stream::operator <<
* @param val
* @return
*/
pdu_stream& pdu_stream::operator<< (const int16_t& val)
{
writeType<int16_t>(val);
return *this;
}
/**
* @brief pdu_stream::operator >>
* @param val
* @return
*/
pdu_stream& pdu_stream::operator>> (int32_t& val)
{
val = readType<int32_t>();
return *this;
}
/**
* @brief pdu_stream::operator <<
* @param val
* @return
*/
pdu_stream& pdu_stream::operator<< (const int32_t& val)
{
writeType<int32_t>(val);
return *this;
}
/**
* @brief pdu_stream::operator >>
* @param val
* @return
*/
pdu_stream& pdu_stream::operator>> (int64_t& val)
{
val = readType<int64_t>();
return *this;
}
/**
* @brief pdu_stream::operator <<
* @param val
* @return
*/
pdu_stream& pdu_stream::operator<< (const int64_t& val)
{
writeType<int64_t>(val);
return *this;
}
/**
* @brief pdu_stream::operator >>
* @brief bufferstream::operator >>
* @param uuid
* @return
*/
pdu_stream& pdu_stream::operator>> (UUID::uuid& uuid)
bufferstream& operator>> (bufferstream& s, UUID::uuid& uuid)
{
uint8_t buffer[UUID_LENGTH];
read(buffer, UUID_LENGTH);
if (gcount() != UUID_LENGTH)
uint8_t buffer[UUID_LENGTH];
s.read(buffer, UUID_LENGTH);
if (s.gcount() != UUID_LENGTH)
{
setstate(std::ios_base::failbit);
return *this;
s.setstate(std::ios_base::failbit);
return s;
}
uuid.setBytes(buffer);
return *this;
uuid.setBytes(buffer);
return s;
};
/**
* @brief pdu_stream::operator <<
* @param obj
* @return
*/
pdu_stream& pdu_stream::operator<< (const pdu_stream_object& obj)
{
obj.oStream(shared_from_this());
return *this;
}
/**
* @brief pdu_stream::operator <<
* @param val
* @return
*/
pdu_stream& pdu_stream::operator<< (const uint8_t& val)
{
writeType<uint8_t>(val);
return *this;
}
/**
* @brief pdu_stream::operator <<
* @param val
* @return
*/
pdu_stream& pdu_stream::operator<< (const uint16_t& val)
{
writeType<uint16_t>(val);
return *this;
}
/**
* @brief pdu_stream::operator <<
* @param val
* @return
*/
pdu_stream& pdu_stream::operator<< (const uint32_t& val)
{
writeType<uint32_t>(val);
return *this;
}
/**
* @brief pdu_stream::operator <<
* @param val
* @return
*/
pdu_stream& pdu_stream::operator<< (const uint64_t& val)
{
writeType<uint64_t>(val);
return *this;
}
/**
* @brief pdu_stream::operator <<
* @brief bufferstream::operator <<
* @param uuid
* @return
*/
pdu_stream& pdu_stream::operator<< (const UUID::uuid& uuid)
bufferstream& operator<< (bufferstream& s, const UUID::uuid& uuid)
{
write(uuid.bytes(), UUID_LENGTH);
return *this;
s.write(uuid.bytes(), UUID_LENGTH);
return s;
}
} // PDU
} // ACN

View File

@ -23,128 +23,18 @@
*/
#pragma once
#include "uuid.h"
#include <memory>
#include <iostream>
#include <bufferstream.h>
#include <uuid.h>
namespace ACN::PDU {
struct pdu_stream_object; // forward declare
/**
* @brief Input/Output stream of nested PDU
*/
class pdu_stream
: public std::enable_shared_from_this<pdu_stream>
, private std::basic_streambuf<uint8_t>
, public std::basic_iostream<uint8_t>
{
public:
pdu_stream(uint8_t * p, std::streamsize l);
// input sequence
uint32_t available();
uint8_t * data();
// output sequence
uint32_t size();
uint8_t * base();
// stream objects
pdu_stream& operator>> (pdu_stream_object& obj);
pdu_stream& operator<< (const pdu_stream_object& obj);
// unsigned integer
pdu_stream& operator>> (uint8_t& val);
pdu_stream& operator<< (const uint8_t& val);
pdu_stream& operator>> (uint16_t& val);
pdu_stream& operator<< (const uint16_t& val);
pdu_stream& operator>> (uint32_t& val);
pdu_stream& operator<< (const uint32_t& val);
pdu_stream& operator>> (uint64_t& val);
pdu_stream& operator<< (const uint64_t& val);
// signed integer
pdu_stream& operator>> (int8_t& val);
pdu_stream& operator<< (const int8_t& val);
pdu_stream& operator>> (int16_t& val);
pdu_stream& operator<< (const int16_t& val);
pdu_stream& operator>> (int32_t& val);
pdu_stream& operator<< (const int32_t& val);
pdu_stream& operator>> (int64_t& val);
pdu_stream& operator<< (const int64_t& val);
// uuid
pdu_stream& operator>> (UUID::uuid& uuid);
pdu_stream& operator<< (const UUID::uuid& uuid);
// strings
void readString(std::string& str, const int fixed_length = 0);
void writeString(const std::string& str, const size_t fixed_length = 0,
const bool terminated = true);
// reinterpreted i/o
/**
* @brief readType
* @return T
*/
template<typename T>
T readType()
{
if (in_avail() < sizeof(T))
setstate(std::ios_base::failbit);
if (!good())
return 0;
T ret = 0;
auto data = reinterpret_cast<uint8_t*>(&ret);
for (int i = sizeof(T); --i >= 0; )
data[i] = get();
if (!in_avail())
setstate(std::ios_base::eofbit);
return ret;
}
/**
* @brief writeType
* @param val
*/
template<typename T>
void writeType (const T& val)
{
auto data = reinterpret_cast<const uint8_t*>(&val);
for (int i = sizeof(T); --i >= 0; )
put(data[i]);
}
};
/**
* @brief A shared pointer to pdu_stream.
*/
using Stream = std::shared_ptr<pdu_stream>;
/**
* @brief The inheritable base of data objects that can be read from and written to a pdu_stream.
*/
struct pdu_stream_object
{
virtual ~pdu_stream_object() {};
/**
* @brief streamSize
* @return length (count of octets) on the wire
*/
virtual size_t streamSize() const = 0;
/**
* @brief fill structure data from input stream
*/
virtual void iStream(Stream) = 0;
/**
* @brief write structure data to output stream
*/
virtual void oStream(Stream) const = 0;
};
using Stream = std::shared_ptr<bufferstream>;
} // ACN::PDU
bufferstream& operator>>(bufferstream&, UUID::uuid&);
bufferstream& operator<<(bufferstream&, const UUID::uuid&);

View File

@ -189,7 +189,7 @@ void Pdu::iStream(Stream stream)
return stream->setstate(std::ios_base::failbit);
// create a stream buffer for the header and data
stream_ = Stream(new pdu_stream(stream->data(), hd_length));
stream_ = Stream(new bufferstream(stream->data(), hd_length));
if (stream_->available() != hd_length)
return stream->setstate(std::ios_base::failbit);

View File

@ -23,10 +23,12 @@
*/
#pragma once
#include "pdu-stream.h"
#include <functional>
#include <memory>
#include <vector>
#include "pdu-stream.h"
/**
* @brief @cite ACN 1.2.8.1 Common Packet Format
@ -43,13 +45,13 @@ class Pdu; // forward declare
/**
* @brief The pdu_header struct
*/
struct pdu_header : public pdu_stream_object {};
struct pdu_header : public streamable {};
/**
* @brief The pdu_data struct
*/
struct pdu_data : public pdu_stream_object {};
struct pdu_data : public streamable {};
/**

View File

@ -98,7 +98,7 @@ void Component::rlpSendUdp (const uint32_t vector,
/// Fills an output stream with the transported PDU
size_t length = transport.streamSize();
uint8_t buffer[length];
PDU::Stream stream(new PDU::pdu_stream(buffer, length));
PDU::Stream stream(new bufferstream(buffer, length));
*stream << transport;
/// Platform devices shall impliment the sending on the network.
@ -158,7 +158,7 @@ void Component::rlpSendTcp (const uint32_t vector,
/// Fills an output stream with the transported PDU
size_t length = transport.streamSize();
uint8_t buffer[length];
PDU::Stream stream(new PDU::pdu_stream(buffer, length));
PDU::Stream stream(new bufferstream(buffer, length));
*stream << transport;
/// Platform devices shall impliment the sending on the network.

View File

@ -69,7 +69,7 @@ public:
* @brief The message_transport struct
*/
struct message_transport
: PDU::pdu_stream_object
: streamable
{
PDU::Block<RLP::Pdu> root; //!< root PDU block

View File

@ -141,7 +141,7 @@ public:
* @brief 4.4.1.2 Channel Parameter Block
*/
struct params
: PDU::pdu_stream_object
: streamable
{
uint8_t Expiry; //!< number of seconds without traffic before leaving
union {
@ -280,7 +280,7 @@ struct get_sessions_data
* 4.4.9.2 Channel Member Info Block
*/
struct channel_info_block
: PDU::pdu_stream_object
: streamable
{
MID mid; //!< MID
UUID::uuid owner; //!< channel owner UUID

View File

@ -48,7 +48,7 @@ static const uint16_t SDT_MULTICAST_PORT = 5568; // IANA registered “sdt”
* @brief 3 Address Specification
*/
struct ipAddress
: PDU::pdu_stream_object
: streamable
{
ipAddress()
: type(0) // SDT_ADDR_NULL

View File

@ -44,7 +44,7 @@ public:
* @brief The module_identifier struct
*/
struct module_identifier
: PDU::pdu_stream_object
: streamable
{
uint16_t manufacturer; //!< ESTA manufactuer ID
uint16_t number; //!< manufacturer's model number
@ -89,7 +89,7 @@ public:
* @brief The point_description struct
*/
struct point_description
: PDU::pdu_stream_object
: streamable
{
uint8_t system; //!< system number
uint16_t group; //!< group number

View File

@ -24,6 +24,7 @@
#pragma once
#include "pdu.h"
#include "uuid.h"
namespace OTP::Layer {
@ -54,7 +55,7 @@ struct base_data
* @brief The base_footer struct
*/
struct base_footer
: PDU::pdu_stream_object
: streamable
{
uint8_t options; //!< options
uint8_t length; //!< length

View File

@ -88,7 +88,7 @@ void pdu::iStream(Stream stream)
return stream->setstate(std::ios_base::failbit);
// create a stream buffer for the data
stream_ = Stream(new ACN::PDU::pdu_stream(stream->data(), length));
stream_ = Stream(new bufferstream(stream->data(), length));
if (stream_->available() != length)
return stream->setstate(std::ios_base::failbit);

View File

@ -30,12 +30,11 @@ namespace OTP {
namespace PDU {
using ACN::PDU::Stream;
using ACN::PDU::pdu_stream_object;
/**
* @brief The pdu_data struct
*/
struct pdu_data : pdu_stream_object {};
struct pdu_data : streamable {};
class pdu;

View File

@ -413,7 +413,7 @@ void transform_data::oStream(PDU::Stream stream) const
* @param t
* @return
*/
ACN::PDU::pdu_stream& operator>>(ACN::PDU::pdu_stream& s, OTP::Transform::Timestamp& t)
bufferstream& operator>>(bufferstream& s, OTP::Transform::Timestamp& t)
{
const auto us = std::chrono::microseconds(s.readType<uint64_t>());
t = OTP::Transform::Timestamp(us);
@ -427,7 +427,7 @@ ACN::PDU::pdu_stream& operator>>(ACN::PDU::pdu_stream& s, OTP::Transform::Timest
* @param t
* @return
*/
ACN::PDU::pdu_stream& operator<<(ACN::PDU::pdu_stream&s, const OTP::Transform::Timestamp& t)
bufferstream& operator<<(bufferstream& s, const OTP::Transform::Timestamp& t)
{
const auto d = t.time_since_epoch();
const auto us = std::chrono::duration_cast<std::chrono::microseconds>(d);

View File

@ -37,7 +37,7 @@ namespace Point {
* @brief The address struct
*/
struct address
: PDU::pdu_stream_object
: streamable
{
uint8_t system; //!< system referance number
uint16_t group; //!< group referance number
@ -80,7 +80,7 @@ public:
};
struct module : PDU::pdu_stream_object {};
struct module : streamable {};
/**
@ -283,7 +283,7 @@ struct transform_data
void oStream(PDU::Stream) const override;
};
ACN::PDU::pdu_stream& operator>>(ACN::PDU::pdu_stream&, OTP::Transform::Timestamp&);
ACN::PDU::pdu_stream& operator<<(ACN::PDU::pdu_stream&, const OTP::Transform::Timestamp&);
bufferstream& operator>>(bufferstream&, OTP::Transform::Timestamp&);
bufferstream& operator<<(bufferstream&, const OTP::Transform::Timestamp&);
} // namespace OTP::Transform

View File

@ -118,7 +118,7 @@ public:
* @brief The connection_flags union
*/
struct connection_flags
: ACN::PDU::pdu_stream_object
: streamable
{
bool incrementalUpdates; //!< incremental updates
uint8_t flags_reserved; //!< Brokers shall ignore.
@ -213,7 +213,7 @@ struct client_redirect_ipv6_data
* @brief The dynamic_uid_request struct
*/
struct dynamic_uid_request
: ACN::PDU::pdu_stream_object
: streamable
{
RDM::UID uid; //!< UID
@ -243,7 +243,7 @@ struct request_dynamic_uid_data
* @brief The dynamic_uid_mapping struct
*/
struct dynamic_uid_mapping
: ACN::PDU::pdu_stream_object
: streamable
{
RDM::UID uid; //!< UID

View File

@ -16,7 +16,7 @@ target_sources(${PROJECT_NAME}
target_link_libraries(${PROJECT_NAME}
PUBLIC
LCP::UUID
LCP::ACN::PDU
LCP::RDM
LCP::RDMNET::RPT
)

View File

@ -76,7 +76,7 @@ namespace ProbeRequest {
* LLRP Target.
*/
struct filter_t
: ACN::PDU::pdu_stream_object
: streamable
{
bool client_tcp_inactive; //!< filter inactive clients
bool brokers_only; //!< only brokers

View File

@ -31,7 +31,7 @@
* @param id
* @return
*/
ACN::PDU::pdu_stream& operator>>(ACN::PDU::pdu_stream& is, RDM::UID& id)
bufferstream& operator>>(bufferstream& is, RDM::UID& id)
{
is >> id.device;
is >> id.manufacturer;
@ -45,7 +45,7 @@ ACN::PDU::pdu_stream& operator>>(ACN::PDU::pdu_stream& is, RDM::UID& id)
* @param id
* @return
*/
ACN::PDU::pdu_stream& operator<<(ACN::PDU::pdu_stream& os, const RDM::UID& id)
bufferstream& operator<<(bufferstream& os, const RDM::UID& id)
{
os << id.device;
os << id.manufacturer;

View File

@ -62,5 +62,5 @@ public:
} // namespace RDMNet
ACN::PDU::pdu_stream& operator>>(ACN::PDU::pdu_stream&, RDM::UID&);
ACN::PDU::pdu_stream& operator<<(ACN::PDU::pdu_stream&, const RDM::UID&);
bufferstream& operator>>(bufferstream&, RDM::UID&);
bufferstream& operator<<(bufferstream&, const RDM::UID&);

View File

@ -18,6 +18,7 @@ target_sources(${PROJECT_NAME}
)
target_link_libraries(${PROJECT_NAME}
PUBLIC
LCP::ACN::PDU
LCP::UUID
LCP::RDM
)

View File

@ -43,7 +43,7 @@ namespace sACN::DATA {
* > the packet is used.
*/
struct data_options
: ACN::PDU::pdu_stream_object
: streamable
{
union {
uint8_t byte;

View File

@ -115,7 +115,7 @@ TEST_F(sACNdataTest, stream_in) {
for (int seq = 1; seq < 4; seq++)
{
e131_data[111] = seq; // sequence number
ACN::PDU::Stream stream(new ACN::PDU::pdu_stream(e131_data, sizeof(e131_data)));
ACN::PDU::Stream stream(new bufferstream(e131_data, sizeof(e131_data)));
ASSERT_EQ(stream->data(), e131_data) << "failed to create stream";
node.UdpPayloadReceiver(stream);
}