| Index: device/nfc/nfc_ndef_record.cc
|
| diff --git a/device/nfc/nfc_ndef_record.cc b/device/nfc/nfc_ndef_record.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f8ac0873fedfe37e9f29423b8d91012509905d7c
|
| --- /dev/null
|
| +++ b/device/nfc/nfc_ndef_record.cc
|
| @@ -0,0 +1,213 @@
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "device/nfc/nfc_ndef_record.h"
|
| +
|
| +#include <map>
|
| +
|
| +#include "base/logging.h"
|
| +
|
| +using base::DictionaryValue;
|
| +using base::ListValue;
|
| +
|
| +namespace device {
|
| +
|
| +namespace {
|
| +
|
| +typedef std::map<std::string, base::Value::Type> FieldValueMap;
|
| +
|
| +bool CheckFieldsAreValid(
|
| + const FieldValueMap& required_fields,
|
| + const FieldValueMap& optional_fields,
|
| + const DictionaryValue* data) {
|
| + size_t required_count = 0;
|
| + for (DictionaryValue::Iterator iter(*data);
|
| + !iter.IsAtEnd(); iter.Advance()) {
|
| + FieldValueMap::const_iterator field_iter =
|
| + required_fields.find(iter.key());
|
| + if (field_iter == required_fields.end()) {
|
| + // Field wasn't one of the required fields. Check if optional.
|
| + field_iter = optional_fields.find(iter.key());
|
| +
|
| + if (field_iter == optional_fields.end()) {
|
| + // If the field isn't one of the optional fields either, then it's
|
| + // invalid.
|
| + VLOG(1) << "Tried to populate record with invalid field: "
|
| + << iter.key();
|
| + return false;
|
| + }
|
| + } else {
|
| + required_count++;
|
| + }
|
| + // The field is invalid, if the type of its value is incorrect.
|
| + if (field_iter->second != iter.value().GetType()) {
|
| + VLOG(1) << "Provided value for field \"" << iter.key() << "\" has type "
|
| + << iter.value().GetType() << ", expected: "
|
| + << field_iter->second;
|
| + return false;
|
| + }
|
| + }
|
| + // Check for required fields.
|
| + if (required_count != required_fields.size()) {
|
| + VLOG(1) << "Provided data did not contain all required fields for "
|
| + << "requested NDEF type.";
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +// Verifies that the contents of |data| conform to the fields of NDEF type
|
| +// "Text".
|
| +bool HandleTypeText(const DictionaryValue* data) {
|
| + VLOG(1) << "Populating record with type \"Text\".";
|
| + FieldValueMap required_fields;
|
| + required_fields[NfcNdefRecord::kFieldText] = base::Value::TYPE_STRING;
|
| + FieldValueMap optional_fields;
|
| + optional_fields[NfcNdefRecord::kFieldEncoding] = base::Value::TYPE_STRING;
|
| + optional_fields[NfcNdefRecord::kFieldLanguageCode] = base::Value::TYPE_STRING;
|
| + if (!CheckFieldsAreValid(required_fields, optional_fields, data)) {
|
| + VLOG(1) << "Failed to populate record.";
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +// Verifies that the contents of |data| conform to the fields of NDEF type
|
| +// "SmartPoster".
|
| +bool HandleTypeSmartPoster(const DictionaryValue* data) {
|
| + VLOG(1) << "Populating record with type \"SmartPoster\".";
|
| + FieldValueMap required_fields;
|
| + required_fields[NfcNdefRecord::kFieldURI] = base::Value::TYPE_STRING;
|
| + FieldValueMap optional_fields;
|
| + optional_fields[NfcNdefRecord::kFieldAction] = base::Value::TYPE_STRING;
|
| + optional_fields[NfcNdefRecord::kFieldMimeType] = base::Value::TYPE_STRING;
|
| + // base::Value restricts the number types to BOOL, INTEGER, and DOUBLE only.
|
| + // uint32 will automatically get converted to a double. "target size" is
|
| + // really a uint32 but we define it as a double for this reason.
|
| + // (See dbus/values_util.h).
|
| + optional_fields[NfcNdefRecord::kFieldTargetSize] = base::Value::TYPE_DOUBLE;
|
| + optional_fields[NfcNdefRecord::kFieldTitles] = base::Value::TYPE_LIST;
|
| + if (!CheckFieldsAreValid(required_fields, optional_fields, data)) {
|
| + VLOG(1) << "Failed to populate record.";
|
| + return false;
|
| + }
|
| + // Verify that the "titles" field was formatted correctly, if it exists.
|
| + const ListValue* titles = NULL;
|
| + if (data->GetList(NfcNdefRecord::kFieldTitles, &titles)) {
|
| + if (titles->empty()) {
|
| + VLOG(1) << "\"titles\" field of SmartPoster is empty.";
|
| + return false;
|
| + }
|
| + for (ListValue::const_iterator iter = titles->begin();
|
| + iter != titles->end(); ++iter) {
|
| + const DictionaryValue* title_data = NULL;
|
| + if (!(*iter)->GetAsDictionary(&title_data)) {
|
| + VLOG(1) << "\"title\" entry for SmartPoster contains an invalid value "
|
| + << "type";
|
| + return false;
|
| + }
|
| + if (!HandleTypeText(title_data)) {
|
| + VLOG(1) << "Badly formatted \"title\" entry for SmartPoster.";
|
| + return false;
|
| + }
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +// Verifies that the contents of |data| conform to the fields of NDEF type
|
| +// "URI".
|
| +bool HandleTypeUri(const DictionaryValue* data) {
|
| + VLOG(1) << "Populating record with type \"URI\".";
|
| + FieldValueMap required_fields;
|
| + required_fields[NfcNdefRecord::kFieldURI] = base::Value::TYPE_STRING;
|
| + FieldValueMap optional_fields;
|
| + optional_fields[NfcNdefRecord::kFieldMimeType] = base::Value::TYPE_STRING;
|
| + optional_fields[NfcNdefRecord::kFieldTargetSize] = base::Value::TYPE_DOUBLE;
|
| + if (!CheckFieldsAreValid(required_fields, optional_fields, data)) {
|
| + VLOG(1) << "Failed to populate record.";
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +// static
|
| +const char NfcNdefRecord::kFieldEncoding[] = "encoding";
|
| +// static
|
| +const char NfcNdefRecord::kFieldLanguageCode[] = "languageCode";
|
| +// static
|
| +const char NfcNdefRecord::kFieldText[] = "text";
|
| +// static
|
| +const char NfcNdefRecord::kFieldURI[] = "uri";
|
| +// static
|
| +const char NfcNdefRecord::kFieldMimeType[] = "mimeType";
|
| +// static
|
| +const char NfcNdefRecord::kFieldTargetSize[] = "targetSize";
|
| +// static
|
| +const char NfcNdefRecord::kFieldTitles[] = "titles";
|
| +// static
|
| +const char NfcNdefRecord::kFieldAction[] = "action";
|
| +// static
|
| +const char NfcNdefRecord::kEncodingUtf8[] = "UTF-8";
|
| +// static
|
| +const char NfcNdefRecord::kEncodingUtf16[] = "UTF-16";
|
| +// static
|
| +const char NfcNdefRecord::kSmartPosterActionDo[] = "do";
|
| +// static
|
| +const char NfcNdefRecord::kSmartPosterActionSave[] = "save";
|
| +// static
|
| +const char NfcNdefRecord::kSmartPosterActionOpen[] = "open";
|
| +
|
| +NfcNdefRecord::NfcNdefRecord() : type_(kTypeUnknown) {
|
| +}
|
| +
|
| +NfcNdefRecord::~NfcNdefRecord() {
|
| +}
|
| +
|
| +bool NfcNdefRecord::IsPopulated() const {
|
| + return type_ != kTypeUnknown;
|
| +}
|
| +
|
| +bool NfcNdefRecord::Populate(Type type, const DictionaryValue* data) {
|
| + if (IsPopulated())
|
| + return false;
|
| +
|
| + DCHECK(data_.empty());
|
| +
|
| + // At this time, only "Text", "URI", and "SmartPoster" are supported.
|
| + bool result = false;
|
| + switch (type) {
|
| + case kTypeText:
|
| + result = HandleTypeText(data);
|
| + break;
|
| + case kTypeSmartPoster:
|
| + result = HandleTypeSmartPoster(data);
|
| + break;
|
| + case kTypeURI:
|
| + result = HandleTypeUri(data);
|
| + break;
|
| + default:
|
| + VLOG(1) << "Unsupported NDEF type: " << type;
|
| + break;
|
| + }
|
| + if (!result)
|
| + return false;
|
| + type_ = type;
|
| + data_.MergeDictionary(data);
|
| + return true;
|
| +}
|
| +
|
| +NfcNdefMessage::NfcNdefMessage() {
|
| +}
|
| +
|
| +NfcNdefMessage::~NfcNdefMessage() {
|
| +}
|
| +
|
| +void NfcNdefMessage::AddRecord(NfcNdefRecord* record) {
|
| + records_.push_back(record);
|
| +}
|
| +
|
| +} // namespace device
|
|
|