diff --git a/features/nfc/nfc/ndef/MessageBuilder.h b/features/nfc/nfc/ndef/MessageBuilder.h index 27b130a838..a170c4f38b 100644 --- a/features/nfc/nfc/ndef/MessageBuilder.h +++ b/features/nfc/nfc/ndef/MessageBuilder.h @@ -38,6 +38,31 @@ namespace ndef { class MessageBuilder { 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& buffer) const = 0; + + protected: + /** + * Non virtual destructor. + */ + ~PayloadBuilder() { } + }; + /** * Create a new MessageBuilder that can be used to construct valid NDEF * messages. @@ -67,6 +92,27 @@ public: 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. * @@ -78,7 +124,23 @@ public: * size remaining in the message buffer is not large enough to makes the * 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. @@ -107,17 +169,17 @@ public: private: // 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_payload_length(const Record &); + void append_payload_length(const Record &, const PayloadBuilder*); void append_id_length(const Record &); void append_type(const Record &); void append_id(const Record &); - void append_payload(const Record &); + void append_payload(const Record &, const PayloadBuilder*); // helpers - static size_t compute_record_size(const Record &record); - static bool is_short_payload(const Record &record); + static bool is_short_payload(const Record &record, const PayloadBuilder*); + static size_t get_payload_size(const Record &, const PayloadBuilder*); // builder state. Span _message_buffer; diff --git a/features/nfc/source/nfc/ndef/MessageBuilder.cpp b/features/nfc/source/nfc/ndef/MessageBuilder.cpp index ca824acbb0..d3de3a2640 100644 --- a/features/nfc/source/nfc/ndef/MessageBuilder.cpp +++ b/features/nfc/source/nfc/ndef/MessageBuilder.cpp @@ -47,7 +47,24 @@ bool MessageBuilder::append_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) { return false; @@ -88,7 +105,7 @@ bool MessageBuilder::append_record(const Record &record) return false; } - if (!record.payload.empty()) { + if (get_payload_size(record, builder)) { return false; } } @@ -107,18 +124,18 @@ bool MessageBuilder::append_record(const Record &record) 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)) { return false; } - append_header(record); + append_header(record, builder); append_type_length(record); - append_payload_length(record); + append_payload_length(record, builder); append_id_length(record); append_type(record); append_id(record); - append_payload(record); + append_payload(record, builder); if (record.chunk) { _in_chunk = true; @@ -161,12 +178,12 @@ Span 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; record_size = 1; /* header */ 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()) { 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.id.size(); - record_size += record.payload.size(); + record_size += get_payload_size(record, builder); return record_size; } -void MessageBuilder::append_header(const Record &record) +void MessageBuilder::append_header(const Record &record, const PayloadBuilder *builder) { uint8_t header = 0; if (!_message_started) { @@ -196,7 +213,7 @@ void MessageBuilder::append_header(const Record &record) header |= Header::chunk_flag_bit; } - if (is_short_payload(record)) { + if (is_short_payload(record, builder)) { header |= Header::short_record_bit; } @@ -213,18 +230,13 @@ void MessageBuilder::append_type_length(const Record &record) _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()) { - _message_buffer[_position++] = 0; - return; - } + size_t size = get_payload_size(record, builder); - if (is_short_payload(record)) { - _message_buffer[_position++] = record.payload.size(); + if (is_short_payload(record, builder)) { + _message_buffer[_position++] = size; } else { - // TODO: proper host to network - uint32_t size = record.payload.size(); _message_buffer[_position++] = (size >> 24) & 0xFF; _message_buffer[_position++] = (size >> 16) & 0xFF; _message_buffer[_position++] = (size >> 8) & 0xFF; @@ -269,29 +281,40 @@ void MessageBuilder::append_id(const Record &record) _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; } - memcpy( - _message_buffer.data() + _position, - record.payload.data(), - record.payload.size() - ); - _position += record.payload.size(); + if (builder) { + builder->build(_message_buffer.subspan(_position, size)); + } else { + memcpy( + _message_buffer.data() + _position, + 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; } else { return false; } } +size_t MessageBuilder::get_payload_size(const Record &record, const PayloadBuilder *builder) +{ + return builder ? builder->size() : record.payload.size(); +} + } // namespace ndef } // namespace nfc } // namespace mbed