OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "device/nfc/nfc_ndef_record.h" |
| 6 |
| 7 #include <map> |
| 8 |
| 9 #include "base/logging.h" |
| 10 |
| 11 using base::DictionaryValue; |
| 12 using base::ListValue; |
| 13 |
| 14 namespace device { |
| 15 |
| 16 namespace { |
| 17 |
| 18 typedef std::map<std::string, base::Value::Type> FieldValueMap; |
| 19 |
| 20 bool CheckFieldsAreValid( |
| 21 const FieldValueMap& required_fields, |
| 22 const FieldValueMap& optional_fields, |
| 23 const DictionaryValue* data) { |
| 24 size_t required_count = 0; |
| 25 for (DictionaryValue::Iterator iter(*data); |
| 26 !iter.IsAtEnd(); iter.Advance()) { |
| 27 FieldValueMap::const_iterator field_iter = |
| 28 required_fields.find(iter.key()); |
| 29 if (field_iter == required_fields.end()) { |
| 30 // Field wasn't one of the required fields. Check if optional. |
| 31 field_iter = optional_fields.find(iter.key()); |
| 32 |
| 33 if (field_iter == optional_fields.end()) { |
| 34 // If the field isn't one of the optional fields either, then it's |
| 35 // invalid. |
| 36 VLOG(1) << "Tried to populate record with invalid field: " |
| 37 << iter.key(); |
| 38 return false; |
| 39 } |
| 40 } else { |
| 41 required_count++; |
| 42 } |
| 43 // The field is invalid, if the type of its value is incorrect. |
| 44 if (field_iter->second != iter.value().GetType()) { |
| 45 VLOG(1) << "Provided value for field \"" << iter.key() << "\" has type " |
| 46 << iter.value().GetType() << ", expected: " |
| 47 << field_iter->second; |
| 48 return false; |
| 49 } |
| 50 } |
| 51 // Check for required fields. |
| 52 if (required_count != required_fields.size()) { |
| 53 VLOG(1) << "Provided data did not contain all required fields for " |
| 54 << "requested NDEF type."; |
| 55 return false; |
| 56 } |
| 57 return true; |
| 58 } |
| 59 |
| 60 // Verifies that the contents of |data| conform to the fields of NDEF type |
| 61 // "Text". |
| 62 bool HandleTypeText(const DictionaryValue* data) { |
| 63 VLOG(1) << "Populating record with type \"Text\"."; |
| 64 FieldValueMap required_fields; |
| 65 required_fields[NfcNdefRecord::kFieldText] = base::Value::TYPE_STRING; |
| 66 FieldValueMap optional_fields; |
| 67 optional_fields[NfcNdefRecord::kFieldEncoding] = base::Value::TYPE_STRING; |
| 68 optional_fields[NfcNdefRecord::kFieldLanguageCode] = base::Value::TYPE_STRING; |
| 69 if (!CheckFieldsAreValid(required_fields, optional_fields, data)) { |
| 70 VLOG(1) << "Failed to populate record."; |
| 71 return false; |
| 72 } |
| 73 return true; |
| 74 } |
| 75 |
| 76 // Verifies that the contents of |data| conform to the fields of NDEF type |
| 77 // "SmartPoster". |
| 78 bool HandleTypeSmartPoster(const DictionaryValue* data) { |
| 79 VLOG(1) << "Populating record with type \"SmartPoster\"."; |
| 80 FieldValueMap required_fields; |
| 81 required_fields[NfcNdefRecord::kFieldURI] = base::Value::TYPE_STRING; |
| 82 FieldValueMap optional_fields; |
| 83 optional_fields[NfcNdefRecord::kFieldAction] = base::Value::TYPE_STRING; |
| 84 optional_fields[NfcNdefRecord::kFieldMimeType] = base::Value::TYPE_STRING; |
| 85 // base::Value restricts the number types to BOOL, INTEGER, and DOUBLE only. |
| 86 // uint32 will automatically get converted to a double. "target size" is |
| 87 // really a uint32 but we define it as a double for this reason. |
| 88 // (See dbus/values_util.h). |
| 89 optional_fields[NfcNdefRecord::kFieldTargetSize] = base::Value::TYPE_DOUBLE; |
| 90 optional_fields[NfcNdefRecord::kFieldTitles] = base::Value::TYPE_LIST; |
| 91 if (!CheckFieldsAreValid(required_fields, optional_fields, data)) { |
| 92 VLOG(1) << "Failed to populate record."; |
| 93 return false; |
| 94 } |
| 95 // Verify that the "titles" field was formatted correctly, if it exists. |
| 96 const ListValue* titles = NULL; |
| 97 if (data->GetList(NfcNdefRecord::kFieldTitles, &titles)) { |
| 98 if (titles->empty()) { |
| 99 VLOG(1) << "\"titles\" field of SmartPoster is empty."; |
| 100 return false; |
| 101 } |
| 102 for (ListValue::const_iterator iter = titles->begin(); |
| 103 iter != titles->end(); ++iter) { |
| 104 const DictionaryValue* title_data = NULL; |
| 105 if (!(*iter)->GetAsDictionary(&title_data)) { |
| 106 VLOG(1) << "\"title\" entry for SmartPoster contains an invalid value " |
| 107 << "type"; |
| 108 return false; |
| 109 } |
| 110 if (!HandleTypeText(title_data)) { |
| 111 VLOG(1) << "Badly formatted \"title\" entry for SmartPoster."; |
| 112 return false; |
| 113 } |
| 114 } |
| 115 } |
| 116 return true; |
| 117 } |
| 118 |
| 119 // Verifies that the contents of |data| conform to the fields of NDEF type |
| 120 // "URI". |
| 121 bool HandleTypeUri(const DictionaryValue* data) { |
| 122 VLOG(1) << "Populating record with type \"URI\"."; |
| 123 FieldValueMap required_fields; |
| 124 required_fields[NfcNdefRecord::kFieldURI] = base::Value::TYPE_STRING; |
| 125 FieldValueMap optional_fields; |
| 126 optional_fields[NfcNdefRecord::kFieldMimeType] = base::Value::TYPE_STRING; |
| 127 optional_fields[NfcNdefRecord::kFieldTargetSize] = base::Value::TYPE_DOUBLE; |
| 128 if (!CheckFieldsAreValid(required_fields, optional_fields, data)) { |
| 129 VLOG(1) << "Failed to populate record."; |
| 130 return false; |
| 131 } |
| 132 return true; |
| 133 } |
| 134 |
| 135 } // namespace |
| 136 |
| 137 // static |
| 138 const char NfcNdefRecord::kFieldEncoding[] = "encoding"; |
| 139 // static |
| 140 const char NfcNdefRecord::kFieldLanguageCode[] = "languageCode"; |
| 141 // static |
| 142 const char NfcNdefRecord::kFieldText[] = "text"; |
| 143 // static |
| 144 const char NfcNdefRecord::kFieldURI[] = "uri"; |
| 145 // static |
| 146 const char NfcNdefRecord::kFieldMimeType[] = "mimeType"; |
| 147 // static |
| 148 const char NfcNdefRecord::kFieldTargetSize[] = "targetSize"; |
| 149 // static |
| 150 const char NfcNdefRecord::kFieldTitles[] = "titles"; |
| 151 // static |
| 152 const char NfcNdefRecord::kFieldAction[] = "action"; |
| 153 // static |
| 154 const char NfcNdefRecord::kEncodingUtf8[] = "UTF-8"; |
| 155 // static |
| 156 const char NfcNdefRecord::kEncodingUtf16[] = "UTF-16"; |
| 157 // static |
| 158 const char NfcNdefRecord::kSmartPosterActionDo[] = "do"; |
| 159 // static |
| 160 const char NfcNdefRecord::kSmartPosterActionSave[] = "save"; |
| 161 // static |
| 162 const char NfcNdefRecord::kSmartPosterActionOpen[] = "open"; |
| 163 |
| 164 NfcNdefRecord::NfcNdefRecord() : type_(kTypeUnknown) { |
| 165 } |
| 166 |
| 167 NfcNdefRecord::~NfcNdefRecord() { |
| 168 } |
| 169 |
| 170 bool NfcNdefRecord::IsPopulated() const { |
| 171 return type_ != kTypeUnknown; |
| 172 } |
| 173 |
| 174 bool NfcNdefRecord::Populate(Type type, const DictionaryValue* data) { |
| 175 if (IsPopulated()) |
| 176 return false; |
| 177 |
| 178 DCHECK(data_.empty()); |
| 179 |
| 180 // At this time, only "Text", "URI", and "SmartPoster" are supported. |
| 181 bool result = false; |
| 182 switch (type) { |
| 183 case kTypeText: |
| 184 result = HandleTypeText(data); |
| 185 break; |
| 186 case kTypeSmartPoster: |
| 187 result = HandleTypeSmartPoster(data); |
| 188 break; |
| 189 case kTypeURI: |
| 190 result = HandleTypeUri(data); |
| 191 break; |
| 192 default: |
| 193 VLOG(1) << "Unsupported NDEF type: " << type; |
| 194 break; |
| 195 } |
| 196 if (!result) |
| 197 return false; |
| 198 type_ = type; |
| 199 data_.MergeDictionary(data); |
| 200 return true; |
| 201 } |
| 202 |
| 203 NfcNdefMessage::NfcNdefMessage() { |
| 204 } |
| 205 |
| 206 NfcNdefMessage::~NfcNdefMessage() { |
| 207 } |
| 208 |
| 209 void NfcNdefMessage::AddRecord(NfcNdefRecord* record) { |
| 210 records_.push_back(record); |
| 211 } |
| 212 |
| 213 } // namespace device |
OLD | NEW |