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_util.h"
32 namespace addressinput
{
36 bool ParseToken(char c
, AddressField
* field
) {
37 assert(field
!= NULL
);
49 *field
= DEPENDENT_LOCALITY
;
52 *field
= SORTING_CODE
;
58 *field
= STREET_ADDRESS
;
61 *field
= ORGANIZATION
;
71 // Clears |lines|, parses |format|, and adds the address fields and literals to
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:
81 // {"AX-", POSTAL_CODE, " ", LOCALITY},
84 void ParseAddressFieldsFormat(const std::string
& format
,
85 std::vector
<std::vector
<FormatElement
> >* lines
) {
86 assert(lines
!= NULL
);
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()) {
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,
128 void ParseAddressFieldsRequired(const std::string
& required
,
129 std::vector
<AddressField
>* fields
) {
130 assert(fields
!= NULL
);
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
;
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
;
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
) {}
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
) {
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
)) {
275 ParseJsonRule(*json
);
279 void Rule::ParseJsonRule(const Json
& json_rule
) {
281 if (json_rule
.GetStringValueForKey("key", &value
)) {
285 if (json_rule
.GetStringValueForKey("name", &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
) {
357 case IDENTITY_FIELDS_SIZE
:
363 int Rule::GetInvalidFieldMessageId(AddressField field
) const {
366 return invalid_admin_area_message_id_
;
368 return IDS_LIBADDRESSINPUT_I18N_INVALID_LOCALITY_LABEL
;
369 case DEPENDENT_LOCALITY
:
370 return IDS_LIBADDRESSINPUT_I18N_INVALID_DEPENDENT_LOCALITY_LABEL
;
372 return invalid_postal_code_message_id_
;
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
;
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
];
402 } // namespace addressinput