Remove PlatformFile from profile_browsertest
[chromium-blink-merge.git] / third_party / libaddressinput / chromium / cpp / src / rule.cc
blob791ac9eca651bbba4d68945ffad93ffaafe454c4
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.
15 #include "rule.h"
17 #include <libaddressinput/address_field.h>
18 #include <libaddressinput/util/scoped_ptr.h>
20 #include <cassert>
21 #include <cstddef>
22 #include <string>
23 #include <vector>
25 #include "grit.h"
26 #include "grit/libaddressinput_strings.h"
27 #include "region_data_constants.h"
28 #include "util/json.h"
29 #include "util/string_util.h"
31 namespace i18n {
32 namespace addressinput {
34 namespace {
36 bool ParseToken(char c, AddressField* field) {
37 assert(field != NULL);
38 switch (c) {
39 case 'R':
40 *field = COUNTRY;
41 return true;
42 case 'S':
43 *field = ADMIN_AREA;
44 return true;
45 case 'C':
46 *field = LOCALITY;
47 return true;
48 case 'D':
49 *field = DEPENDENT_LOCALITY;
50 return true;
51 case 'X':
52 *field = SORTING_CODE;
53 return true;
54 case 'Z':
55 *field = POSTAL_CODE;
56 return true;
57 case 'A':
58 *field = STREET_ADDRESS;
59 return true;
60 case 'O':
61 *field = ORGANIZATION;
62 return true;
63 case 'N':
64 *field = RECIPIENT;
65 return true;
66 default:
67 return false;
71 // Clears |lines|, parses |format|, and adds the address fields and literals to
72 // |lines|.
74 // For example, the address format in Finland is "%O%n%N%n%A%nAX-%Z %C%nÅLAND".
75 // It includes the allowed fields prefixed with %, newlines denoted %n, and the
76 // extra text that should be included on an envelope. It is parsed into:
77 // {
78 // {ORGANIZATION},
79 // {RECIPIENT},
80 // {STREET_ADDRESS},
81 // {"AX-", POSTAL_CODE, " ", LOCALITY},
82 // {"ÅLAND"}
83 // }
84 void ParseAddressFieldsFormat(const std::string& format,
85 std::vector<std::vector<FormatElement> >* lines) {
86 assert(lines != NULL);
87 lines->clear();
88 lines->resize(1);
90 std::vector<std::string> format_parts;
91 SplitString(format, '%', &format_parts);
93 // If the address format starts with a literal, then it will be in the first
94 // element of |format_parts|. This literal does not begin with % and should
95 // not be parsed as a token.
96 if (!format_parts.empty() && !format_parts[0].empty()) {
97 lines->back().push_back(FormatElement(format_parts[0]));
100 // The rest of the elements in |format_parts| begin with %.
101 for (size_t i = 1; i < format_parts.size(); ++i) {
102 if (format_parts[i].empty()) {
103 continue;
106 // The first character after % denotes a field or a newline token.
107 const char control_character = format_parts[i][0];
109 // The rest of the string after the token is a literal.
110 const std::string literal = format_parts[i].substr(1);
112 AddressField field = COUNTRY;
113 if (ParseToken(control_character, &field)) {
114 lines->back().push_back(FormatElement(field));
115 } else if (control_character == 'n') {
116 lines->push_back(std::vector<FormatElement>());
119 if (!literal.empty()) {
120 lines->back().push_back(FormatElement(literal));
125 // Clears |fields|, parses |required|, and adds the required fields to |fields|.
126 // For example, parses "SCDX" into {ADMIN_AREA, LOCALITY, DEPENDENT_LOCALITY,
127 // SORTING_CODE}.
128 void ParseAddressFieldsRequired(const std::string& required,
129 std::vector<AddressField>* fields) {
130 assert(fields != NULL);
131 fields->clear();
132 for (size_t i = 0; i < required.length(); ++i) {
133 AddressField field = COUNTRY;
134 if (ParseToken(required[i], &field)) {
135 fields->push_back(field);
140 int GetAdminAreaMessageId(const std::string& admin_area_type, bool error) {
141 if (admin_area_type == "area") {
142 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_AREA
143 : IDS_LIBADDRESSINPUT_I18N_AREA;
145 if (admin_area_type == "county") {
146 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_COUNTY_LABEL
147 : IDS_LIBADDRESSINPUT_I18N_COUNTY_LABEL;
149 if (admin_area_type == "department") {
150 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DEPARTMENT
151 : IDS_LIBADDRESSINPUT_I18N_DEPARTMENT;
153 if (admin_area_type == "district") {
154 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DEPENDENT_LOCALITY_LABEL
155 : IDS_LIBADDRESSINPUT_I18N_DEPENDENT_LOCALITY_LABEL;
157 if (admin_area_type == "do_si") {
158 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DO_SI
159 : IDS_LIBADDRESSINPUT_I18N_DO_SI;
161 if (admin_area_type == "emirate") {
162 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_EMIRATE
163 : IDS_LIBADDRESSINPUT_I18N_EMIRATE;
165 if (admin_area_type == "island") {
166 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_ISLAND
167 : IDS_LIBADDRESSINPUT_I18N_ISLAND;
169 if (admin_area_type == "parish") {
170 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PARISH
171 : IDS_LIBADDRESSINPUT_I18N_PARISH;
173 if (admin_area_type == "prefecture") {
174 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PREFECTURE
175 : IDS_LIBADDRESSINPUT_I18N_PREFECTURE;
177 if (admin_area_type == "province") {
178 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PROVINCE
179 : IDS_LIBADDRESSINPUT_I18N_PROVINCE;
181 if (admin_area_type == "state") {
182 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_STATE_LABEL
183 : IDS_LIBADDRESSINPUT_I18N_STATE_LABEL;
185 return INVALID_MESSAGE_ID;
188 int GetPostalCodeMessageId(const std::string& postal_code_type, bool error) {
189 if (postal_code_type == "postal") {
190 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_POSTAL_CODE_LABEL
191 : IDS_LIBADDRESSINPUT_I18N_POSTAL_CODE_LABEL;
193 if (postal_code_type == "zip") {
194 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_ZIP_CODE_LABEL
195 : IDS_LIBADDRESSINPUT_I18N_ZIP_CODE_LABEL;
197 return INVALID_MESSAGE_ID;
200 } // namespace
202 FormatElement::FormatElement(AddressField field)
203 : field(field), literal() {}
205 FormatElement::FormatElement(const std::string& literal)
206 : field(COUNTRY), literal(literal) {
207 assert(!literal.empty());
210 FormatElement::~FormatElement() {}
212 bool FormatElement::operator==(const FormatElement& other) const {
213 return field == other.field && literal == other.literal;
216 Rule::Rule()
217 : key_(),
218 name_(),
219 latin_name_(),
220 format_(),
221 latin_format_(),
222 required_(),
223 sub_keys_(),
224 sub_names_(),
225 sub_lnames_(),
226 languages_(),
227 input_languages_(),
228 language_(),
229 postal_code_format_(),
230 admin_area_name_message_id_(INVALID_MESSAGE_ID),
231 invalid_admin_area_message_id_(INVALID_MESSAGE_ID),
232 postal_code_name_message_id_(INVALID_MESSAGE_ID),
233 invalid_postal_code_message_id_(INVALID_MESSAGE_ID) {}
235 Rule::~Rule() {}
237 // static
238 const Rule& Rule::GetDefault() {
239 // Allocated once and leaked on shutdown.
240 static Rule* default_rule = NULL;
241 if (default_rule == NULL) {
242 default_rule = new Rule;
243 default_rule->ParseSerializedRule(
244 RegionDataConstants::GetDefaultRegionData());
246 return *default_rule;
249 void Rule::CopyFrom(const Rule& rule) {
250 key_ = rule.key_;
251 name_ = rule.name_;
252 latin_name_ = rule.latin_name_;
253 format_ = rule.format_;
254 latin_format_ = rule.latin_format_;
255 required_ = rule.required_;
256 sub_keys_ = rule.sub_keys_;
257 languages_ = rule.languages_;
258 input_languages_ = rule.input_languages_;
259 language_ = rule.language_;
260 sub_keys_ = rule.sub_keys_;
261 sub_names_ = rule.sub_names_;
262 sub_lnames_ = rule.sub_lnames_;
263 postal_code_format_ = rule.postal_code_format_;
264 admin_area_name_message_id_ = rule.admin_area_name_message_id_;
265 invalid_admin_area_message_id_ = rule.invalid_admin_area_message_id_;
266 postal_code_name_message_id_ = rule.postal_code_name_message_id_;
267 invalid_postal_code_message_id_ = rule.invalid_postal_code_message_id_;
270 bool Rule::ParseSerializedRule(const std::string& serialized_rule) {
271 scoped_ptr<Json> json(Json::Build());
272 if (!json->ParseObject(serialized_rule)) {
273 return false;
275 ParseJsonRule(*json);
276 return true;
279 void Rule::ParseJsonRule(const Json& json_rule) {
280 std::string value;
281 if (json_rule.GetStringValueForKey("key", &value)) {
282 key_.swap(value);
285 if (json_rule.GetStringValueForKey("name", &value)) {
286 name_.swap(value);
289 if (json_rule.GetStringValueForKey("lname", &value)) {
290 latin_name_.swap(value);
293 if (json_rule.GetStringValueForKey("fmt", &value)) {
294 ParseAddressFieldsFormat(value, &format_);
297 if (json_rule.GetStringValueForKey("lfmt", &value)) {
298 ParseAddressFieldsFormat(value, &latin_format_);
301 if (json_rule.GetStringValueForKey("require", &value)) {
302 ParseAddressFieldsRequired(value, &required_);
305 // Used as a separator in a list of items. For example, the list of supported
306 // languages can be "de~fr~it".
307 static const char kSeparator = '~';
308 if (json_rule.GetStringValueForKey("sub_keys", &value)) {
309 SplitString(value, kSeparator, &sub_keys_);
312 if (json_rule.GetStringValueForKey("sub_names", &value)) {
313 SplitString(value, kSeparator, &sub_names_);
314 assert(sub_names_.size() == sub_keys_.size());
317 if (json_rule.GetStringValueForKey("sub_lnames", &value)) {
318 SplitString(value, kSeparator, &sub_lnames_);
319 assert(sub_lnames_.size() == sub_keys_.size());
322 if (json_rule.GetStringValueForKey("languages", &value)) {
323 SplitString(value, kSeparator, &languages_);
326 if (json_rule.GetStringValueForKey("input_languages", &value)) {
327 SplitString(value, kSeparator, &input_languages_);
330 if (json_rule.GetStringValueForKey("lang", &value)) {
331 language_.swap(value);
334 if (json_rule.GetStringValueForKey("zip", &value)) {
335 postal_code_format_.swap(value);
338 if (json_rule.GetStringValueForKey("state_name_type", &value)) {
339 admin_area_name_message_id_ = GetAdminAreaMessageId(value, false);
340 invalid_admin_area_message_id_ = GetAdminAreaMessageId(value, true);
343 if (json_rule.GetStringValueForKey("zip_name_type", &value)) {
344 postal_code_name_message_id_ = GetPostalCodeMessageId(value, false);
345 invalid_postal_code_message_id_ = GetPostalCodeMessageId(value, true);
349 const std::string& Rule::GetIdentityField(IdentityField identity_field) const {
350 switch (identity_field) {
351 case KEY:
352 return key_;
353 case NAME:
354 return name_;
355 case LATIN_NAME:
356 return latin_name_;
357 case IDENTITY_FIELDS_SIZE:
358 assert(false);
360 return key_;
363 int Rule::GetInvalidFieldMessageId(AddressField field) const {
364 switch (field) {
365 case ADMIN_AREA:
366 return invalid_admin_area_message_id_;
367 case LOCALITY:
368 return IDS_LIBADDRESSINPUT_I18N_INVALID_LOCALITY_LABEL;
369 case DEPENDENT_LOCALITY:
370 return IDS_LIBADDRESSINPUT_I18N_INVALID_DEPENDENT_LOCALITY_LABEL;
371 case POSTAL_CODE:
372 return invalid_postal_code_message_id_;
373 default:
374 return IDS_LIBADDRESSINPUT_I18N_INVALID_ENTRY;
378 bool Rule::CanonicalizeSubKey(const std::string& user_input,
379 std::string* sub_key) const {
380 if (sub_keys_.empty()) {
381 *sub_key = user_input;
382 return true;
385 return GetMatchingSubKey(user_input, sub_keys_, sub_key) ||
386 GetMatchingSubKey(user_input, sub_names_, sub_key) ||
387 GetMatchingSubKey(user_input, sub_lnames_, sub_key);
390 bool Rule::GetMatchingSubKey(const std::string& target,
391 const std::vector<std::string>& values,
392 std::string* sub_key) const {
393 for (size_t i = 0; i < values.size(); ++i) {
394 if (LooseStringCompare(values[i], target)) {
395 *sub_key = sub_keys_[i];
396 return true;
399 return false;
402 } // namespace addressinput
403 } // namespace i18n