Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / libaddressinput / chromium / cpp / src / rule.cc
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%nÅLAND".
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