This source file includes following definitions.
- ValidateURI
- CheckFieldsAreValid
- HandleTypeText
- HandleTypeSmartPoster
- HandleTypeUri
- IsPopulated
- Populate
- AddRecord
- RemoveRecord
#include "device/nfc/nfc_ndef_record.h"
#include <map>
#include "base/logging.h"
#include "url/gurl.h"
using base::DictionaryValue;
using base::ListValue;
namespace device {
namespace {
typedef std::map<std::string, base::Value::Type> FieldValueMap;
bool ValidateURI(const DictionaryValue* data) {
std::string uri;
if (!data->GetString(NfcNdefRecord::kFieldURI, &uri)) {
VLOG(1) << "No URI entry in data.";
return false;
}
DCHECK(!uri.empty());
GURL url(uri);
if (!url.is_valid()) {
LOG(ERROR) << "Invalid URI given: " << uri;
return false;
}
return true;
}
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_iter = optional_fields.find(iter.key());
if (field_iter == optional_fields.end()) {
VLOG(1) << "Tried to populate record with invalid field: "
<< iter.key();
return false;
}
} else {
required_count++;
}
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;
}
std::string string_value;
if (iter.value().GetAsString(&string_value) && string_value.empty()) {
VLOG(1) << "Empty value given for field of type string: " << iter.key();
return false;
}
}
if (required_count != required_fields.size()) {
VLOG(1) << "Provided data did not contain all required fields for "
<< "requested NDEF type.";
return false;
}
return true;
}
bool HandleTypeText(const DictionaryValue* data) {
VLOG(1) << "Populating record with type \"Text\".";
FieldValueMap required_fields;
required_fields[NfcNdefRecord::kFieldText] = base::Value::TYPE_STRING;
required_fields[NfcNdefRecord::kFieldEncoding] = base::Value::TYPE_STRING;
required_fields[NfcNdefRecord::kFieldLanguageCode] = base::Value::TYPE_STRING;
FieldValueMap optional_fields;
if (!CheckFieldsAreValid(required_fields, optional_fields, data)) {
VLOG(1) << "Failed to populate record.";
return false;
}
std::string encoding;
if (!data->GetString(NfcNdefRecord::kFieldEncoding, &encoding)) {
if (encoding != NfcNdefRecord::kEncodingUtf8 ||
encoding != NfcNdefRecord::kEncodingUtf16) {
VLOG(1) << "Invalid \"Encoding\" value:" << encoding;
return false;
}
}
return true;
}
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;
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;
}
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 ValidateURI(data);
}
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 ValidateURI(data);
}
}
const char NfcNdefRecord::kFieldEncoding[] = "encoding";
const char NfcNdefRecord::kFieldLanguageCode[] = "languageCode";
const char NfcNdefRecord::kFieldText[] = "text";
const char NfcNdefRecord::kFieldURI[] = "uri";
const char NfcNdefRecord::kFieldMimeType[] = "mimeType";
const char NfcNdefRecord::kFieldTargetSize[] = "targetSize";
const char NfcNdefRecord::kFieldTitles[] = "titles";
const char NfcNdefRecord::kFieldAction[] = "action";
const char NfcNdefRecord::kEncodingUtf8[] = "UTF-8";
const char NfcNdefRecord::kEncodingUtf16[] = "UTF-16";
const char NfcNdefRecord::kSmartPosterActionDo[] = "do";
const char NfcNdefRecord::kSmartPosterActionSave[] = "save";
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());
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);
}
bool NfcNdefMessage::RemoveRecord(NfcNdefRecord* record) {
for (RecordList::iterator iter = records_.begin();
iter != records_.end(); ++iter) {
if (*iter == record) {
records_.erase(iter);
return true;
}
}
return false;
}
}