NFC: Add payload builder into ndef::MessageBuilder

pull/7822/head
Vincent Coubard 2018-08-28 17:25:56 +01:00
parent b5bfcc3fcb
commit b6e604338e
2 changed files with 121 additions and 36 deletions

View File

@ -38,6 +38,31 @@ namespace ndef {
class MessageBuilder { class MessageBuilder {
public: public:
/**
* Build a record payload.
*/
struct PayloadBuilder {
/**
* Return the size of the payload built by this object.
*
* @return The size of the payload.
*/
virtual size_t size() const = 0;
/**
* Build the payload in a buffer that has the required size.
*
* @param buffer The buffer used to construct the payload.
*/
virtual void build(const Span<uint8_t>& buffer) const = 0;
protected:
/**
* Non virtual destructor.
*/
~PayloadBuilder() { }
};
/** /**
* Create a new MessageBuilder that can be used to construct valid NDEF * Create a new MessageBuilder that can be used to construct valid NDEF
* messages. * messages.
@ -67,6 +92,27 @@ public:
bool is_last_record = false bool is_last_record = false
); );
/**
* Append a new record to the message being built.
*
* @param type The type of the record to insert.
* @param builder The builder of the payload.
* @param is_last_record true if the record to insert is the last record of
* the payload or false otherwise.
*
* @return true if the record has been successfully inserted or false
* otherwise.
*
* @note insertion can fail if the message is already complete or if the
* size remaining in the message buffer is not large enough to makes the
* record inserted fit.
*/
bool append_record(
const RecordType &type,
const PayloadBuilder &builder,
bool is_last_record = false
);
/** /**
* Append a new record to the message being built. * Append a new record to the message being built.
* *
@ -78,7 +124,23 @@ public:
* size remaining in the message buffer is not large enough to makes the * size remaining in the message buffer is not large enough to makes the
* record inserted fit. * record inserted fit.
*/ */
bool append_record(const Record &record); bool append_record(
const Record &record,
const PayloadBuilder *builder = NULL
);
/**
* Compute the size of a record.
*
* @param record The record used to compute the size.
* @param builder The payload builder if any.
*
* @return The size of the payload for the record in input.
*/
static size_t compute_record_size(
const Record &record,
const PayloadBuilder* builder = NULL
);
/** /**
* Reset the builder state. * Reset the builder state.
@ -107,17 +169,17 @@ public:
private: private:
// append fields // append fields
void append_header(const Record &record); void append_header(const Record &record, const PayloadBuilder*);
void append_type_length(const Record &record); void append_type_length(const Record &record);
void append_payload_length(const Record &); void append_payload_length(const Record &, const PayloadBuilder*);
void append_id_length(const Record &); void append_id_length(const Record &);
void append_type(const Record &); void append_type(const Record &);
void append_id(const Record &); void append_id(const Record &);
void append_payload(const Record &); void append_payload(const Record &, const PayloadBuilder*);
// helpers // helpers
static size_t compute_record_size(const Record &record); static bool is_short_payload(const Record &record, const PayloadBuilder*);
static bool is_short_payload(const Record &record); static size_t get_payload_size(const Record &, const PayloadBuilder*);
// builder state. // builder state.
Span<uint8_t> _message_buffer; Span<uint8_t> _message_buffer;

View File

@ -47,7 +47,24 @@ bool MessageBuilder::append_record(
return append_record(record); return append_record(record);
} }
bool MessageBuilder::append_record(const Record &record) bool MessageBuilder::append_record(
const RecordType &type,
const PayloadBuilder &builder,
bool is_last_record
) {
Record record(
type,
RecordPayload(),
RecordID(),
/* chunk */ false,
is_last_record
);
return append_record(record, &builder);
}
bool MessageBuilder::append_record(const Record &record, const PayloadBuilder *builder)
{ {
if (_message_ended) { if (_message_ended) {
return false; return false;
@ -88,7 +105,7 @@ bool MessageBuilder::append_record(const Record &record)
return false; return false;
} }
if (!record.payload.empty()) { if (get_payload_size(record, builder)) {
return false; return false;
} }
} }
@ -107,18 +124,18 @@ bool MessageBuilder::append_record(const Record &record)
return false; return false;
} }
size_t record_size = compute_record_size(record); size_t record_size = compute_record_size(record, builder);
if (record_size > (_message_buffer.size() - _position)) { if (record_size > (_message_buffer.size() - _position)) {
return false; return false;
} }
append_header(record); append_header(record, builder);
append_type_length(record); append_type_length(record);
append_payload_length(record); append_payload_length(record, builder);
append_id_length(record); append_id_length(record);
append_type(record); append_type(record);
append_id(record); append_id(record);
append_payload(record); append_payload(record, builder);
if (record.chunk) { if (record.chunk) {
_in_chunk = true; _in_chunk = true;
@ -161,12 +178,12 @@ Span<const uint8_t> MessageBuilder::get_message() const
} }
} }
size_t MessageBuilder::compute_record_size(const Record &record) size_t MessageBuilder::compute_record_size(const Record &record, const PayloadBuilder *builder)
{ {
size_t record_size = 0; size_t record_size = 0;
record_size = 1; /* header */ record_size = 1; /* header */
record_size += 1; /* type length */ record_size += 1; /* type length */
record_size += is_short_payload(record) ? 1 : 4; record_size += is_short_payload(record, builder) ? 1 : 4;
if (!record.id.empty()) { if (!record.id.empty()) {
record_size += 1; record_size += 1;
@ -174,12 +191,12 @@ size_t MessageBuilder::compute_record_size(const Record &record)
record_size += record.type.value.size(); record_size += record.type.value.size();
record_size += record.id.size(); record_size += record.id.size();
record_size += record.payload.size(); record_size += get_payload_size(record, builder);
return record_size; return record_size;
} }
void MessageBuilder::append_header(const Record &record) void MessageBuilder::append_header(const Record &record, const PayloadBuilder *builder)
{ {
uint8_t header = 0; uint8_t header = 0;
if (!_message_started) { if (!_message_started) {
@ -196,7 +213,7 @@ void MessageBuilder::append_header(const Record &record)
header |= Header::chunk_flag_bit; header |= Header::chunk_flag_bit;
} }
if (is_short_payload(record)) { if (is_short_payload(record, builder)) {
header |= Header::short_record_bit; header |= Header::short_record_bit;
} }
@ -213,18 +230,13 @@ void MessageBuilder::append_type_length(const Record &record)
_message_buffer[_position++] = record.type.value.size(); _message_buffer[_position++] = record.type.value.size();
} }
void MessageBuilder::append_payload_length(const Record &record) void MessageBuilder::append_payload_length(const Record &record, const PayloadBuilder *builder)
{ {
if (record.payload.empty()) { size_t size = get_payload_size(record, builder);
_message_buffer[_position++] = 0;
return;
}
if (is_short_payload(record)) { if (is_short_payload(record, builder)) {
_message_buffer[_position++] = record.payload.size(); _message_buffer[_position++] = size;
} else { } else {
// TODO: proper host to network
uint32_t size = record.payload.size();
_message_buffer[_position++] = (size >> 24) & 0xFF; _message_buffer[_position++] = (size >> 24) & 0xFF;
_message_buffer[_position++] = (size >> 16) & 0xFF; _message_buffer[_position++] = (size >> 16) & 0xFF;
_message_buffer[_position++] = (size >> 8) & 0xFF; _message_buffer[_position++] = (size >> 8) & 0xFF;
@ -269,29 +281,40 @@ void MessageBuilder::append_id(const Record &record)
_position += record.id.size(); _position += record.id.size();
} }
void MessageBuilder::append_payload(const Record &record) void MessageBuilder::append_payload(const Record &record, const PayloadBuilder *builder)
{ {
if (record.payload.empty()) { size_t size = get_payload_size(record, builder);
if (!size) {
return; return;
} }
memcpy( if (builder) {
_message_buffer.data() + _position, builder->build(_message_buffer.subspan(_position, size));
record.payload.data(), } else {
record.payload.size() memcpy(
); _message_buffer.data() + _position,
_position += record.payload.size(); record.payload.data(),
size
);
}
_position += size;
} }
bool MessageBuilder::is_short_payload(const Record &record) bool MessageBuilder::is_short_payload(const Record &record, const PayloadBuilder *builder)
{ {
if (record.payload.size() <= 255) { if (get_payload_size(record, builder) <= 255) {
return true; return true;
} else { } else {
return false; return false;
} }
} }
size_t MessageBuilder::get_payload_size(const Record &record, const PayloadBuilder *builder)
{
return builder ? builder->size() : record.payload.size();
}
} // namespace ndef } // namespace ndef
} // namespace nfc } // namespace nfc
} // namespace mbed } // namespace mbed