Upstream version 5.34.104.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 "grit.h"
26 #include "grit/libaddressinput_strings.h"
27 #include "region_data_constants.h"
28 #include "util/json.h"
29 #include "util/string_compare.h"
30 #include "util/string_split.h"
31
32 namespace i18n {
33 namespace addressinput {
34
35 namespace {
36
37 bool ParseToken(char c, AddressField* field) {
38   assert(field != NULL);
39   switch (c) {
40     case 'R':
41       *field = COUNTRY;
42       return true;
43     case 'S':
44       *field = ADMIN_AREA;
45       return true;
46     case 'C':
47       *field = LOCALITY;
48       return true;
49     case 'D':
50       *field = DEPENDENT_LOCALITY;
51       return true;
52     case 'X':
53       *field = SORTING_CODE;
54       return true;
55     case 'Z':
56       *field = POSTAL_CODE;
57       return true;
58     case 'A':
59       *field = STREET_ADDRESS;
60       return true;
61     case 'O':
62       *field = ORGANIZATION;
63       return true;
64     case 'N':
65       *field = RECIPIENT;
66       return true;
67     default:
68       return false;
69   }
70 }
71
72 // Clears |lines|, parses |format|, and adds the address fields and literals to
73 // |lines|.
74 //
75 // For example, the address format in Finland is "%O%n%N%n%A%nAX-%Z %C%nÅLAND".
76 // It includes the allowed fields prefixed with %, newlines denoted %n, and the
77 // extra text that should be included on an envelope. It is parsed into:
78 // {
79 //     {ORGANIZATION},
80 //     {RECIPIENT},
81 //     {STREET_ADDRESS},
82 //     {"AX-", POSTAL_CODE, " ", LOCALITY},
83 //     {"ÅLAND"}
84 // }
85 void ParseAddressFieldsFormat(const std::string& format,
86                               std::vector<std::vector<FormatElement> >* lines) {
87   assert(lines != NULL);
88   lines->clear();
89   lines->resize(1);
90
91   std::vector<std::string> format_parts;
92   SplitString(format, '%', &format_parts);
93
94   // If the address format starts with a literal, then it will be in the first
95   // element of |format_parts|. This literal does not begin with % and should
96   // not be parsed as a token.
97   if (!format_parts.empty() && !format_parts[0].empty()) {
98     lines->back().push_back(FormatElement(format_parts[0]));
99   }
100
101   // The rest of the elements in |format_parts| begin with %.
102   for (size_t i = 1; i < format_parts.size(); ++i) {
103     if (format_parts[i].empty()) {
104       continue;
105     }
106
107     // The first character after % denotes a field or a newline token.
108     const char control_character = format_parts[i][0];
109
110     // The rest of the string after the token is a literal.
111     const std::string literal = format_parts[i].substr(1);
112
113     AddressField field = COUNTRY;
114     if (ParseToken(control_character, &field)) {
115       lines->back().push_back(FormatElement(field));
116     } else if (control_character == 'n') {
117       lines->push_back(std::vector<FormatElement>());
118     }
119
120     if (!literal.empty()) {
121       lines->back().push_back(FormatElement(literal));
122     }
123   }
124 }
125
126 // Clears |fields|, parses |required|, and adds the required fields to |fields|.
127 // For example, parses "SCDX" into {ADMIN_AREA, LOCALITY, DEPENDENT_LOCALITY,
128 // SORTING_CODE}.
129 void ParseAddressFieldsRequired(const std::string& required,
130                                 std::vector<AddressField>* fields) {
131   assert(fields != NULL);
132   fields->clear();
133   for (size_t i = 0; i < required.length(); ++i) {
134     AddressField field = COUNTRY;
135     if (ParseToken(required[i], &field)) {
136       fields->push_back(field);
137     }
138   }
139 }
140
141 int GetAdminAreaMessageId(const std::string& admin_area_type, bool error) {
142   if (admin_area_type == "area") {
143     return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_AREA
144                  : IDS_LIBADDRESSINPUT_I18N_AREA;
145   }
146   if (admin_area_type == "county") {
147     return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_COUNTY_LABEL
148                  : IDS_LIBADDRESSINPUT_I18N_COUNTY_LABEL;
149   }
150   if (admin_area_type == "department") {
151     return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DEPARTMENT
152                  : IDS_LIBADDRESSINPUT_I18N_DEPARTMENT;
153   }
154   if (admin_area_type == "district") {
155     return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DEPENDENT_LOCALITY_LABEL
156                  : IDS_LIBADDRESSINPUT_I18N_DEPENDENT_LOCALITY_LABEL;
157   }
158   if (admin_area_type == "do_si") {
159     return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DO_SI
160                  : IDS_LIBADDRESSINPUT_I18N_DO_SI;
161   }
162   if (admin_area_type == "emirate") {
163     return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_EMIRATE
164                  : IDS_LIBADDRESSINPUT_I18N_EMIRATE;
165   }
166   if (admin_area_type == "island") {
167     return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_ISLAND
168                  : IDS_LIBADDRESSINPUT_I18N_ISLAND;
169   }
170   if (admin_area_type == "parish") {
171     return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PARISH
172                  : IDS_LIBADDRESSINPUT_I18N_PARISH;
173   }
174   if (admin_area_type == "prefecture") {
175     return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PREFECTURE
176                  : IDS_LIBADDRESSINPUT_I18N_PREFECTURE;
177   }
178   if (admin_area_type == "province") {
179     return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PROVINCE
180                  : IDS_LIBADDRESSINPUT_I18N_PROVINCE;
181   }
182   if (admin_area_type == "state") {
183     return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_STATE_LABEL
184                  : IDS_LIBADDRESSINPUT_I18N_STATE_LABEL;
185   }
186   return INVALID_MESSAGE_ID;
187 }
188
189 int GetPostalCodeMessageId(const std::string& postal_code_type, bool error) {
190   if (postal_code_type == "postal") {
191     return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_POSTAL_CODE_LABEL
192                  : IDS_LIBADDRESSINPUT_I18N_POSTAL_CODE_LABEL;
193   }
194   if (postal_code_type == "zip") {
195     return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_ZIP_CODE_LABEL
196                  : IDS_LIBADDRESSINPUT_I18N_ZIP_CODE_LABEL;
197   }
198   return INVALID_MESSAGE_ID;
199 }
200
201 }  // namespace
202
203 FormatElement::FormatElement(AddressField field)
204     : field(field), literal() {}
205
206 FormatElement::FormatElement(const std::string& literal)
207     : field(COUNTRY), literal(literal) {
208   assert(!literal.empty());
209 }
210
211 FormatElement::~FormatElement() {}
212
213 bool FormatElement::operator==(const FormatElement& other) const {
214   return field == other.field && literal == other.literal;
215 }
216
217 Rule::Rule()
218     : format_(),
219       required_(),
220       sub_keys_(),
221       languages_(),
222       language_(),
223       postal_code_format_(),
224       admin_area_name_message_id_(INVALID_MESSAGE_ID),
225       postal_code_name_message_id_(INVALID_MESSAGE_ID) {}
226
227 Rule::~Rule() {}
228
229 // static
230 const Rule& Rule::GetDefault() {
231   // Allocated once and leaked on shutdown.
232   static Rule* default_rule = NULL;
233   if (default_rule == NULL) {
234     default_rule = new Rule;
235     default_rule->ParseSerializedRule(
236         RegionDataConstants::GetDefaultRegionData());
237   }
238   return *default_rule;
239 }
240
241 void Rule::CopyFrom(const Rule& rule) {
242   format_ = rule.format_;
243   required_ = rule.required_;
244   sub_keys_ = rule.sub_keys_;
245   languages_ = rule.languages_;
246   language_ = rule.language_;
247   postal_code_format_ = rule.postal_code_format_;
248   admin_area_name_message_id_ = rule.admin_area_name_message_id_;
249   invalid_admin_area_message_id_ = rule.invalid_admin_area_message_id_;
250   postal_code_name_message_id_ = rule.postal_code_name_message_id_;
251   invalid_postal_code_message_id_ = rule.invalid_postal_code_message_id_;
252 }
253
254 bool Rule::ParseSerializedRule(const std::string& serialized_rule) {
255   scoped_ptr<Json> json(Json::Build());
256   if (!json->ParseObject(serialized_rule)) {
257     return false;
258   }
259   ParseJsonRule(*json);
260   return true;
261 }
262
263 void Rule::ParseJsonRule(const Json& json_rule) {
264   std::string value;
265   if (json_rule.GetStringValueForKey("fmt", &value)) {
266     ParseAddressFieldsFormat(value, &format_);
267   }
268
269   if (json_rule.GetStringValueForKey("require", &value)) {
270     ParseAddressFieldsRequired(value, &required_);
271   }
272
273   // Used as a separator in a list of items. For example, the list of supported
274   // languages can be "de~fr~it".
275   static const char kSeparator = '~';
276   if (json_rule.GetStringValueForKey("sub_keys", &value)) {
277     SplitString(value, kSeparator, &sub_keys_);
278   }
279
280   if (json_rule.GetStringValueForKey("sub_names", &value)) {
281     SplitString(value, kSeparator, &sub_names_);
282     assert(sub_names_.size() == sub_keys_.size());
283   }
284
285   if (json_rule.GetStringValueForKey("sub_lnames", &value)) {
286     SplitString(value, kSeparator, &sub_lnames_);
287     assert(sub_lnames_.size() == sub_keys_.size());
288   }
289
290   if (json_rule.GetStringValueForKey("languages", &value)) {
291     SplitString(value, kSeparator, &languages_);
292   }
293
294   if (json_rule.GetStringValueForKey("lang", &value)) {
295     language_.swap(value);
296   }
297
298   if (json_rule.GetStringValueForKey("zip", &value)) {
299     postal_code_format_.swap(value);
300   }
301
302   if (json_rule.GetStringValueForKey("state_name_type", &value)) {
303     admin_area_name_message_id_ = GetAdminAreaMessageId(value, false);
304     invalid_admin_area_message_id_ = GetAdminAreaMessageId(value, true);
305   }
306
307   if (json_rule.GetStringValueForKey("zip_name_type", &value)) {
308     postal_code_name_message_id_ = GetPostalCodeMessageId(value, false);
309     invalid_postal_code_message_id_ = GetPostalCodeMessageId(value, true);
310   }
311 }
312
313 int Rule::GetInvalidFieldMessageId(AddressField field) const {
314   switch (field) {
315     case ADMIN_AREA:
316       return invalid_admin_area_message_id_;
317     case LOCALITY:
318       return IDS_LIBADDRESSINPUT_I18N_INVALID_LOCALITY_LABEL;
319     case DEPENDENT_LOCALITY:
320       return IDS_LIBADDRESSINPUT_I18N_INVALID_DEPENDENT_LOCALITY_LABEL;
321     case POSTAL_CODE:
322       return invalid_postal_code_message_id_;
323     default:
324       return IDS_LIBADDRESSINPUT_I18N_INVALID_ENTRY;
325   }
326 }
327
328 bool Rule::CanonicalizeSubKey(const std::string& user_input,
329                               std::string* sub_key) const {
330   if (sub_keys_.empty()) {
331     *sub_key = user_input;
332     return true;
333   }
334
335   return GetMatchingSubKey(user_input, sub_keys_, sub_key) ||
336       GetMatchingSubKey(user_input, sub_names_, sub_key) ||
337       GetMatchingSubKey(user_input, sub_lnames_, sub_key);
338 }
339
340 bool Rule::GetMatchingSubKey(const std::string& target,
341                              const std::vector<std::string>& values,
342                              std::string* sub_key) const {
343   for (size_t i = 0; i < values.size(); ++i) {
344     if (LooseStringCompare(values[i], target)) {
345       *sub_key = sub_keys_[i];
346       return true;
347     }
348   }
349   return false;
350 }
351
352 }  // namespace addressinput
353 }  // namespace i18n