1 // Copyright (C) 2013 Google Inc.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <libaddressinput/address_field.h>
18 #include <libaddressinput/util/scoped_ptr.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"
33 namespace addressinput {
37 bool ParseToken(char c, AddressField* field) {
38 assert(field != NULL);
50 *field = DEPENDENT_LOCALITY;
53 *field = SORTING_CODE;
59 *field = STREET_ADDRESS;
62 *field = ORGANIZATION;
72 // Clears |lines|, parses |format|, and adds the address fields and literals to
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:
82 // {"AX-", POSTAL_CODE, " ", LOCALITY},
85 void ParseAddressFieldsFormat(const std::string& format,
86 std::vector<std::vector<FormatElement> >* lines) {
87 assert(lines != NULL);
91 std::vector<std::string> format_parts;
92 SplitString(format, '%', &format_parts);
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]));
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()) {
107 // The first character after % denotes a field or a newline token.
108 const char control_character = format_parts[i][0];
110 // The rest of the string after the token is a literal.
111 const std::string literal = format_parts[i].substr(1);
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>());
120 if (!literal.empty()) {
121 lines->back().push_back(FormatElement(literal));
126 // Clears |fields|, parses |required|, and adds the required fields to |fields|.
127 // For example, parses "SCDX" into {ADMIN_AREA, LOCALITY, DEPENDENT_LOCALITY,
129 void ParseAddressFieldsRequired(const std::string& required,
130 std::vector<AddressField>* fields) {
131 assert(fields != NULL);
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);
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;
146 if (admin_area_type == "county") {
147 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_COUNTY_LABEL
148 : IDS_LIBADDRESSINPUT_I18N_COUNTY_LABEL;
150 if (admin_area_type == "department") {
151 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DEPARTMENT
152 : IDS_LIBADDRESSINPUT_I18N_DEPARTMENT;
154 if (admin_area_type == "district") {
155 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DEPENDENT_LOCALITY_LABEL
156 : IDS_LIBADDRESSINPUT_I18N_DEPENDENT_LOCALITY_LABEL;
158 if (admin_area_type == "do_si") {
159 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DO_SI
160 : IDS_LIBADDRESSINPUT_I18N_DO_SI;
162 if (admin_area_type == "emirate") {
163 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_EMIRATE
164 : IDS_LIBADDRESSINPUT_I18N_EMIRATE;
166 if (admin_area_type == "island") {
167 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_ISLAND
168 : IDS_LIBADDRESSINPUT_I18N_ISLAND;
170 if (admin_area_type == "parish") {
171 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PARISH
172 : IDS_LIBADDRESSINPUT_I18N_PARISH;
174 if (admin_area_type == "prefecture") {
175 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PREFECTURE
176 : IDS_LIBADDRESSINPUT_I18N_PREFECTURE;
178 if (admin_area_type == "province") {
179 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PROVINCE
180 : IDS_LIBADDRESSINPUT_I18N_PROVINCE;
182 if (admin_area_type == "state") {
183 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_STATE_LABEL
184 : IDS_LIBADDRESSINPUT_I18N_STATE_LABEL;
186 return INVALID_MESSAGE_ID;
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;
194 if (postal_code_type == "zip") {
195 return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_ZIP_CODE_LABEL
196 : IDS_LIBADDRESSINPUT_I18N_ZIP_CODE_LABEL;
198 return INVALID_MESSAGE_ID;
203 FormatElement::FormatElement(AddressField field)
204 : field(field), literal() {}
206 FormatElement::FormatElement(const std::string& literal)
207 : field(COUNTRY), literal(literal) {
208 assert(!literal.empty());
211 FormatElement::~FormatElement() {}
213 bool FormatElement::operator==(const FormatElement& other) const {
214 return field == other.field && literal == other.literal;
223 postal_code_format_(),
224 admin_area_name_message_id_(INVALID_MESSAGE_ID),
225 postal_code_name_message_id_(INVALID_MESSAGE_ID) {}
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());
238 return *default_rule;
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_;
254 bool Rule::ParseSerializedRule(const std::string& serialized_rule) {
255 scoped_ptr<Json> json(Json::Build());
256 if (!json->ParseObject(serialized_rule)) {
259 ParseJsonRule(*json);
263 void Rule::ParseJsonRule(const Json& json_rule) {
265 if (json_rule.GetStringValueForKey("fmt", &value)) {
266 ParseAddressFieldsFormat(value, &format_);
269 if (json_rule.GetStringValueForKey("require", &value)) {
270 ParseAddressFieldsRequired(value, &required_);
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_);
280 if (json_rule.GetStringValueForKey("sub_names", &value)) {
281 SplitString(value, kSeparator, &sub_names_);
282 assert(sub_names_.size() == sub_keys_.size());
285 if (json_rule.GetStringValueForKey("sub_lnames", &value)) {
286 SplitString(value, kSeparator, &sub_lnames_);
287 assert(sub_lnames_.size() == sub_keys_.size());
290 if (json_rule.GetStringValueForKey("languages", &value)) {
291 SplitString(value, kSeparator, &languages_);
294 if (json_rule.GetStringValueForKey("lang", &value)) {
295 language_.swap(value);
298 if (json_rule.GetStringValueForKey("zip", &value)) {
299 postal_code_format_.swap(value);
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);
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);
313 int Rule::GetInvalidFieldMessageId(AddressField field) const {
316 return invalid_admin_area_message_id_;
318 return IDS_LIBADDRESSINPUT_I18N_INVALID_LOCALITY_LABEL;
319 case DEPENDENT_LOCALITY:
320 return IDS_LIBADDRESSINPUT_I18N_INVALID_DEPENDENT_LOCALITY_LABEL;
322 return invalid_postal_code_message_id_;
324 return IDS_LIBADDRESSINPUT_I18N_INVALID_ENTRY;
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;
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);
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];
352 } // namespace addressinput