Program Listing for File message.cpp

Return to documentation for file (src/message.cpp)

#include "ndef-lite/message.hpp"
#include "ndef-lite/record-header.hpp"
#include "ndef-lite/record-type.hpp"

using namespace std;

NDEFMessage::NDEFMessage(const vector<uint8_t>& data, const NDEFRecordType& type, uint offset)
{
  this->message_records.push_back(NDEFRecord{ data, type, offset });
}

NDEFMessage::NDEFMessage(const NDEFRecord& record) { this->message_records.push_back(record); }

NDEFMessage::NDEFMessage(const NDEFRecordList& records) { this->message_records = records; }

void NDEFMessage::append_record(const NDEFRecord& record) { this->message_records.push_back(record); }

void NDEFMessage::insert_record(const NDEFRecord& record, uint index)
{
  // Have to provide bounds checking
  if (index > this->message_records.size()) {
    throw std::out_of_range{ "Unable to insert record. Index " + to_string(index) + " outside of range of message" };
  }

  this->message_records.emplace(this->message_records.begin() + index, record);
}

void NDEFMessage::remove_record(uint index)
{
  // Have to provide bounds checking
  if (index >= this->message_records.size()) {
    throw std::out_of_range{ "Unable to remove record. Index " + to_string(index) + " outside of range of message" };
  }
  this->message_records.erase(this->message_records.begin() + index);
}

void NDEFMessage::set_record(const NDEFRecord& record, uint index)
{
  // Have to provide bounds checking
  if (index >= this->message_records.size()) {
    throw std::out_of_range{ "Unable to set record. Index " + to_string(index) + " outside of range of message" };
  }
  this->message_records.at(index) = record;
}

bool NDEFMessage::is_valid() const
{
  // Messages must have at least 1 record
  if (this->message_records.empty()) {
    return false;
  }

  // Validate all individual records
  for (auto&& record : this->message_records) {
    if (!record.is_valid()) {
      return false;
    }
  }

  return true;
}

std::vector<uint8_t> NDEFMessage::as_bytes() const
{
  vector<uint8_t> byte_sequence;

  // Can only generate a byte sequence if the message is valid
  if (!this->is_valid()) {
    return byte_sequence;
  }

  // Generate header for each record
  uint8_t header = 0x00;
  size_t num_records = this->message_records.size();
  for (size_t i = 0; i < num_records; i++) {
    // Immutable reference to current record to allow us to retrieve data without changing anything
    auto&& record = this->message_records.at(i);

    // Retrieve individual record's header, then set ME/MB bit flags appropriately
    header = record.header();
    // First record, set Message Begin flag
    header |= (i == 0) ? static_cast<uint8_t>(RecordFlag::MB) : 0;
    // Last record, set Message End flag
    header |= (i == (num_records - 1)) ? static_cast<uint8_t>(RecordFlag::ME) : 0;

    // Create byte sequence, setting MB/ME header flags for record, then add the bytes to the ouput bytes
    auto record_bytes = record.as_bytes(header);
    byte_sequence.insert(byte_sequence.end(), record_bytes.begin(), record_bytes.end());
  }

  return byte_sequence;
}

NDEFMessage NDEFMessage::from_bytes(const std::vector<uint8_t>& data, uint offset)
{
  NDEFMessage msg;

  // NOTE: Potentially should be using a deque due to removal from front of vector
  // Get all bytes after offset position from input
  auto buffer = vector<uint8_t>{ data.begin() + offset, data.end() };

  // Read in all bytes into records
  while (!buffer.empty()) {
    // Number of bytes used by record during creation
    size_t bytes_used = 0;

    // Create record from current byte array (offset already handled)
    auto record = NDEFRecord::from_bytes(buffer, 0, bytes_used);

    // If the record was invalid, then quit now, ignoring all current/remaining bytes
    if (record.type().id() == NDEFRecordType::TypeID::Invalid) {
      break;
    }

    // Record is valid, add it to the message
    msg.append_record(record);

    // Remove bytes read by record creation
    buffer.erase(buffer.begin(), buffer.begin() + bytes_used);
  }

  return msg;
}