1 // Copyright (C) 2013 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "rule.h" 16 17 #include <libaddressinput/address_field.h> 18 #include <libaddressinput/util/scoped_ptr.h> 19 20 #include <cassert> 21 #include <cstddef> 22 #include <string> 23 #include <vector> 24 25 #include "region_data_constants.h" 26 #include "util/json.h" 27 #include "util/string_util.h" 28 29 namespace i18n { 30 namespace addressinput { 31 32 namespace { 33 34 bool ParseToken(char c, AddressField* field) { 35 assert(field != NULL); 36 switch (c) { 37 case 'R': 38 *field = COUNTRY; 39 return true; 40 case 'S': 41 *field = ADMIN_AREA; 42 return true; 43 case 'C': 44 *field = LOCALITY; 45 return true; 46 case 'D': 47 *field = DEPENDENT_LOCALITY; 48 return true; 49 case 'X': 50 *field = SORTING_CODE; 51 return true; 52 case 'Z': 53 *field = POSTAL_CODE; 54 return true; 55 case 'A': 56 *field = STREET_ADDRESS; 57 return true; 58 case 'O': 59 *field = ORGANIZATION; 60 return true; 61 case 'N': 62 *field = RECIPIENT; 63 return true; 64 default: 65 return false; 66 } 67 } 68 69 // Clears |lines|, parses |format|, and adds the address fields and literals to 70 // |lines|. 71 // 72 // For example, the address format in Finland is "%O%n%N%n%A%nAX-%Z %C%nLAND". 73 // It includes the allowed fields prefixed with %, newlines denoted %n, and the 74 // extra text that should be included on an envelope. It is parsed into: 75 // { 76 // {ORGANIZATION}, 77 // {RECIPIENT}, 78 // {STREET_ADDRESS}, 79 // {"AX-", POSTAL_CODE, " ", LOCALITY}, 80 // {"LAND"} 81 // } 82 void ParseAddressFieldsFormat(const std::string& format, 83 std::vector<std::vector<FormatElement> >* lines) { 84 assert(lines != NULL); 85 lines->clear(); 86 lines->resize(1); 87 88 std::vector<std::string> format_parts; 89 SplitString(format, '%', &format_parts); 90 91 // If the address format starts with a literal, then it will be in the first 92 // element of |format_parts|. This literal does not begin with % and should 93 // not be parsed as a token. 94 if (!format_parts.empty() && !format_parts[0].empty()) { 95 lines->back().push_back(FormatElement(format_parts[0])); 96 } 97 98 // The rest of the elements in |format_parts| begin with %. 99 for (size_t i = 1; i < format_parts.size(); ++i) { 100 if (format_parts[i].empty()) { 101 continue; 102 } 103 104 // The first character after % denotes a field or a newline token. 105 const char control_character = format_parts[i][0]; 106 107 // The rest of the string after the token is a literal. 108 const std::string literal = format_parts[i].substr(1); 109 110 AddressField field = COUNTRY; 111 if (ParseToken(control_character, &field)) { 112 lines->back().push_back(FormatElement(field)); 113 } else if (control_character == 'n') { 114 lines->push_back(std::vector<FormatElement>()); 115 } 116 117 if (!literal.empty()) { 118 lines->back().push_back(FormatElement(literal)); 119 } 120 } 121 } 122 123 // Clears |fields|, parses |required|, and adds the required fields to |fields|. 124 // For example, parses "SCDX" into {ADMIN_AREA, LOCALITY, DEPENDENT_LOCALITY, 125 // SORTING_CODE}. 126 void ParseAddressFieldsRequired(const std::string& required, 127 std::vector<AddressField>* fields) { 128 assert(fields != NULL); 129 fields->clear(); 130 for (size_t i = 0; i < required.length(); ++i) { 131 AddressField field = COUNTRY; 132 if (ParseToken(required[i], &field)) { 133 fields->push_back(field); 134 } 135 } 136 } 137 138 // Finds |target| in |values_to_compare| and sets |selected_value| to the 139 // associated value from |values_to_select|. Returns true if |target| is in 140 // |values_to_compare|. |selected_value| should not be NULL. |values_to_compare| 141 // should not be larger than |values_to_select|. 142 bool GetMatchingValue(const std::string& target, 143 const std::vector<std::string>& values_to_compare, 144 const std::vector<std::string>& values_to_select, 145 std::string* selected_value) { 146 assert(selected_value != NULL); 147 assert(values_to_select.size() >= values_to_compare.size()); 148 for (size_t i = 0; i < values_to_compare.size(); ++i) { 149 if (LooseStringCompare(values_to_compare[i], target)) { 150 *selected_value = values_to_select[i]; 151 return true; 152 } 153 } 154 return false; 155 } 156 157 } // namespace 158 159 FormatElement::FormatElement(AddressField field) 160 : field(field), literal() {} 161 162 FormatElement::FormatElement(const std::string& literal) 163 : field(COUNTRY), literal(literal) { 164 assert(!literal.empty()); 165 } 166 167 FormatElement::~FormatElement() {} 168 169 bool FormatElement::operator==(const FormatElement& other) const { 170 return field == other.field && literal == other.literal; 171 } 172 173 Rule::Rule() {} 174 175 Rule::~Rule() {} 176 177 // static 178 const Rule& Rule::GetDefault() { 179 // Allocated once and leaked on shutdown. 180 static Rule* default_rule = NULL; 181 if (default_rule == NULL) { 182 default_rule = new Rule; 183 default_rule->ParseSerializedRule( 184 RegionDataConstants::GetDefaultRegionData()); 185 } 186 return *default_rule; 187 } 188 189 void Rule::CopyFrom(const Rule& rule) { 190 key_ = rule.key_; 191 name_ = rule.name_; 192 latin_name_ = rule.latin_name_; 193 format_ = rule.format_; 194 latin_format_ = rule.latin_format_; 195 required_ = rule.required_; 196 sub_keys_ = rule.sub_keys_; 197 languages_ = rule.languages_; 198 input_languages_ = rule.input_languages_; 199 language_ = rule.language_; 200 sub_keys_ = rule.sub_keys_; 201 sub_names_ = rule.sub_names_; 202 sub_lnames_ = rule.sub_lnames_; 203 postal_code_format_ = rule.postal_code_format_; 204 admin_area_name_type_ = rule.admin_area_name_type_; 205 postal_code_name_type_ = rule.postal_code_name_type_; 206 } 207 208 bool Rule::ParseSerializedRule(const std::string& serialized_rule) { 209 scoped_ptr<Json> json(Json::Build()); 210 if (!json->ParseObject(serialized_rule)) { 211 return false; 212 } 213 ParseJsonRule(*json); 214 return true; 215 } 216 217 void Rule::ParseJsonRule(const Json& json_rule) { 218 std::string value; 219 if (json_rule.GetStringValueForKey("key", &value)) { 220 key_.swap(value); 221 } 222 223 if (json_rule.GetStringValueForKey("name", &value)) { 224 name_.swap(value); 225 } 226 227 if (json_rule.GetStringValueForKey("lname", &value)) { 228 latin_name_.swap(value); 229 } 230 231 if (json_rule.GetStringValueForKey("fmt", &value)) { 232 ParseAddressFieldsFormat(value, &format_); 233 } 234 235 if (json_rule.GetStringValueForKey("lfmt", &value)) { 236 ParseAddressFieldsFormat(value, &latin_format_); 237 } 238 239 if (json_rule.GetStringValueForKey("require", &value)) { 240 ParseAddressFieldsRequired(value, &required_); 241 } 242 243 // Used as a separator in a list of items. For example, the list of supported 244 // languages can be "de~fr~it". 245 static const char kSeparator = '~'; 246 if (json_rule.GetStringValueForKey("sub_keys", &value)) { 247 SplitString(value, kSeparator, &sub_keys_); 248 } 249 250 if (json_rule.GetStringValueForKey("sub_names", &value)) { 251 SplitString(value, kSeparator, &sub_names_); 252 assert(sub_names_.size() == sub_keys_.size()); 253 } 254 255 if (json_rule.GetStringValueForKey("sub_lnames", &value)) { 256 SplitString(value, kSeparator, &sub_lnames_); 257 assert(sub_lnames_.size() == sub_keys_.size()); 258 } 259 260 if (json_rule.GetStringValueForKey("languages", &value)) { 261 SplitString(value, kSeparator, &languages_); 262 } 263 264 if (json_rule.GetStringValueForKey("input_languages", &value)) { 265 SplitString(value, kSeparator, &input_languages_); 266 } 267 268 if (json_rule.GetStringValueForKey("lang", &value)) { 269 language_.swap(value); 270 } 271 272 if (json_rule.GetStringValueForKey("zip", &value)) { 273 postal_code_format_.swap(value); 274 } 275 276 if (json_rule.GetStringValueForKey("state_name_type", &value)) { 277 admin_area_name_type_.swap(value); 278 } 279 280 if (json_rule.GetStringValueForKey("zip_name_type", &value)) { 281 postal_code_name_type_.swap(value); 282 } 283 } 284 285 const std::string& Rule::GetIdentityField(IdentityField identity_field) const { 286 switch (identity_field) { 287 case KEY: 288 return key_; 289 case NAME: 290 return name_; 291 case LATIN_NAME: 292 return latin_name_; 293 case IDENTITY_FIELDS_SIZE: 294 assert(false); 295 } 296 return key_; 297 } 298 299 bool Rule::CanonicalizeSubKey(const std::string& user_input, 300 bool keep_input_latin, 301 std::string* sub_key) const { 302 assert(sub_key != NULL); 303 304 if (sub_keys_.empty()) { 305 *sub_key = user_input; 306 return true; 307 } 308 309 return GetMatchingValue(user_input, sub_keys_, sub_keys_, sub_key) || 310 GetMatchingValue(user_input, sub_names_, sub_keys_, sub_key) || 311 (keep_input_latin && 312 GetMatchingValue(user_input, sub_lnames_, sub_lnames_, sub_key)) || 313 GetMatchingValue(user_input, sub_lnames_, sub_keys_, sub_key); 314 } 315 316 } // namespace addressinput 317 } // namespace i18n 318