diff --git a/src/ArduinoNDEF/field/text_payload.cpp b/src/ArduinoNDEF/field/text_payload.cpp new file mode 100644 index 0000000..4986c25 --- /dev/null +++ b/src/ArduinoNDEF/field/text_payload.cpp @@ -0,0 +1,69 @@ +#include "text_payload.hpp" + +namespace ArduinoNDEF +{ +namespace Field +{ + +TextPayload *TextPayload::from_text(const char *text, const char *language_code) +{ + if (text == nullptr || language_code == nullptr) + return nullptr; + + uint32_t language_code_length = strlen(language_code); + + if (language_code_length != 2 && language_code_length != 5) + return nullptr; + if (language_code_length == 5 && language_code[2] != '-') + return nullptr; + + uint32_t header_length = 1 + language_code_length; + uint8_t header[header_length]; + header[0] = language_code_length; + memcpy(header + 1, language_code, language_code_length); + + uint32_t text_length = strlen(text); + uint32_t payload_length = header_length + text_length; + + auto payload_data = new uint8_t[payload_length]; + if (payload_data == nullptr) + return nullptr; + + memcpy(payload_data, header, header_length); + memcpy(payload_data + header_length, text, text_length); + + return new TextPayload(payload_data, payload_length); +} + +const char *TextPayload::to_text() const +{ + auto language_code_length = _data[0]; + auto header_length = /* language_length */ 1 + /* language */ language_code_length; + auto text_length = _length - header_length; + auto text = new char[text_length + 1]; + + if (text == nullptr) + return nullptr; + + memcpy(text, _data + header_length, text_length); + text[text_length] = '\0'; + + return text; +} + +const char *TextPayload::to_language_code() const +{ + auto language_code_length = _data[0]; + auto language_code = new char[language_code_length + 1]; + + if (language_code == nullptr) + return nullptr; + + memcpy(language_code, _data + 1, language_code_length); + language_code[language_code_length] = '\0'; + + return language_code; +} + +} // namespace Field +} // namespace ArduinoNDEF \ No newline at end of file diff --git a/src/ArduinoNDEF/field/text_payload.hpp b/src/ArduinoNDEF/field/text_payload.hpp new file mode 100644 index 0000000..7bcbd97 --- /dev/null +++ b/src/ArduinoNDEF/field/text_payload.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "payload.hpp" + +namespace ArduinoNDEF +{ +namespace Field +{ + +class TextPayload : public Payload +{ + public: + /** + * @brief Create a NDEF text payload + * @param text The text + * @param language_code The language + * @return A pointer to a new NDEF text payload object + */ + static TextPayload *from_text(const char *text, const char *language_code); + + /** + * @brief Get the text + * @return The text C-string + * @note Memory is allocated for the text string and it is the responsibility of the + * caller to free it + */ + const char *to_text() const; + + /** + * @brief Get the language code + * @return The language code C-string + * @note Memory is allocated for the language code string and it is the + * responsibility of the caller to free it + */ + const char *to_language_code() const; + + private: + TextPayload(const uint8_t *data, uint8_t length) : + Payload(data, length, OwnershipUnique) + { + } +}; + +} // namespace Field +} // namespace ArduinoNDEF \ No newline at end of file diff --git a/src/ArduinoNDEF/record/text.cpp b/src/ArduinoNDEF/record/text.cpp index 3c0d826..9074260 100644 --- a/src/ArduinoNDEF/record/text.cpp +++ b/src/ArduinoNDEF/record/text.cpp @@ -13,37 +13,18 @@ Text *Text::create( const Field::Id &id ) { - // 1. Prepare header - uint32_t language_code_length = strlen(language_code); - - if (language_code_length != 2 && language_code_length != 5) - return nullptr; - if (language_code_length == 5 && language_code[2] != '-') + auto type_field = new Field::Type(Field::Type::RTD_TEXT); + if (type_field == nullptr) return nullptr; - uint32_t header_length = 1 + language_code_length; - uint8_t header[header_length]; - header[0] = language_code_length; - memcpy(header + 1, language_code, language_code_length); - - // 2. Prepare payload - uint32_t text_length = strlen(text); - uint32_t payload_length = header_length + text_length; - - auto payload_data = new uint8_t[payload_length]; - if (payload_data == nullptr) - return nullptr; - - memcpy(payload_data, header, header_length); - memcpy(payload_data + header_length, text, text_length); - - auto type = new Field::Type(Field::Type::RTD_TEXT); - auto payload = - new Field::Payload(payload_data, payload_length, Field::Payload::OwnershipUnique); - if (type == nullptr || payload == nullptr) + auto payload_field = Field::TextPayload::from_text(text, language_code); + if (payload_field == nullptr) + { + delete type_field; return nullptr; + } - return new Text(*type, *payload, is_message_begin, is_message_end, id); + return new Text(*type_field, *payload_field, is_message_begin, is_message_end, id); } Text *Text::create(const char *text, const char *language_code) diff --git a/src/ArduinoNDEF/record/text.hpp b/src/ArduinoNDEF/record/text.hpp index 1a77d24..fdd9780 100644 --- a/src/ArduinoNDEF/record/text.hpp +++ b/src/ArduinoNDEF/record/text.hpp @@ -1,3 +1,4 @@ +#include "../field/text_payload.hpp" #include "../record.hpp" namespace ArduinoNDEF @@ -65,7 +66,7 @@ class Text : public Record private: Text( const Field::Type &type, - const Field::Payload &payload, + const Field::TextPayload &payload, bool is_message_begin, bool is_message_end, const Field::Id &id diff --git a/tests/FieldTest/FieldTest.ino b/tests/FieldTest/FieldTest.ino index 8a1ecc3..81175d1 100644 --- a/tests/FieldTest/FieldTest.ino +++ b/tests/FieldTest/FieldTest.ino @@ -286,6 +286,81 @@ test(uri_payload__no_abbreviation) delete payload; } +test(text_payload__language_code_2_characters) +{ + auto payload = ArduinoNDEF::Field::TextPayload::from_text("Hello, world!", "en"); + assertEqual(payload->length(), static_cast(16)); + assertEqual(payload->data()[0], 0x02); + assertEqual(payload->data()[1], static_cast('e')); + assertEqual(payload->data()[2], static_cast('n')); + assertEqual(payload->data()[3], static_cast('H')); + assertEqual(payload->data()[4], static_cast('e')); + assertEqual(payload->data()[5], static_cast('l')); + assertEqual(payload->data()[6], static_cast('l')); + assertEqual(payload->data()[7], static_cast('o')); + assertEqual(payload->data()[8], static_cast(',')); + assertEqual(payload->data()[9], static_cast(' ')); + assertEqual(payload->data()[10], static_cast('w')); + assertEqual(payload->data()[11], static_cast('o')); + assertEqual(payload->data()[12], static_cast('r')); + assertEqual(payload->data()[13], static_cast('l')); + assertEqual(payload->data()[14], static_cast('d')); + assertEqual(payload->data()[15], static_cast('!')); + auto text = payload->to_text(); + assertEqual(text, "Hello, world!"); + delete[] text; + auto language_code = payload->to_language_code(); + assertEqual(language_code, "en"); + delete[] language_code; + delete payload; +} + +test(text_payload__language_code_5_characters) +{ + auto payload = ArduinoNDEF::Field::TextPayload::from_text("Hello, world!", "en-US"); + assertEqual(payload->length(), static_cast(19)); + assertEqual(payload->data()[0], 0x05); + assertEqual(payload->data()[1], static_cast('e')); + assertEqual(payload->data()[2], static_cast('n')); + assertEqual(payload->data()[3], static_cast('-')); + assertEqual(payload->data()[4], static_cast('U')); + assertEqual(payload->data()[5], static_cast('S')); + assertEqual(payload->data()[6], static_cast('H')); + assertEqual(payload->data()[7], static_cast('e')); + assertEqual(payload->data()[8], static_cast('l')); + assertEqual(payload->data()[9], static_cast('l')); + assertEqual(payload->data()[10], static_cast('o')); + assertEqual(payload->data()[11], static_cast(',')); + assertEqual(payload->data()[12], static_cast(' ')); + assertEqual(payload->data()[13], static_cast('w')); + assertEqual(payload->data()[14], static_cast('o')); + assertEqual(payload->data()[15], static_cast('r')); + assertEqual(payload->data()[16], static_cast('l')); + assertEqual(payload->data()[17], static_cast('d')); + assertEqual(payload->data()[18], static_cast('!')); + auto text = payload->to_text(); + assertEqual(text, "Hello, world!"); + delete[] text; + auto language_code = payload->to_language_code(); + assertEqual(language_code, "en-US"); + delete[] language_code; + delete payload; +} + +test(text_payload__errors) +{ + assertEqual( + ArduinoNDEF::Field::TextPayload::from_text("Hello", "invalid language code"), + nullptr + ); + assertEqual(ArduinoNDEF::Field::TextPayload::from_text("Hello", "abcde"), nullptr); + assertEqual(ArduinoNDEF::Field::TextPayload::from_text(nullptr, "en"), nullptr); + assertEqual( + ArduinoNDEF::Field::TextPayload::from_text("Hello, world!", nullptr), + nullptr + ); +} + void setup() { #if !defined(EPOXY_DUINO)