OLD | NEW |
1 // Copyright (C) 2013 Google Inc. | 1 // Copyright (C) 2013 Google Inc. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with 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 | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 | 14 |
15 #include <libaddressinput/address_validator.h> | 15 #include <libaddressinput/address_validator.h> |
16 | 16 |
| 17 #include <libaddressinput/address_data.h> |
17 #include <libaddressinput/downloader.h> | 18 #include <libaddressinput/downloader.h> |
18 #include <libaddressinput/load_rules_delegate.h> | 19 #include <libaddressinput/load_rules_delegate.h> |
19 #include <libaddressinput/localization.h> | 20 #include <libaddressinput/localization.h> |
20 #include <libaddressinput/storage.h> | 21 #include <libaddressinput/storage.h> |
21 #include <libaddressinput/util/basictypes.h> | 22 #include <libaddressinput/util/basictypes.h> |
22 #include <libaddressinput/util/scoped_ptr.h> | 23 #include <libaddressinput/util/scoped_ptr.h> |
23 | 24 |
| 25 #include <algorithm> |
24 #include <cassert> | 26 #include <cassert> |
25 #include <cstddef> | 27 #include <cstddef> |
26 #include <map> | 28 #include <map> |
27 #include <set> | 29 #include <set> |
28 #include <string> | 30 #include <string> |
29 | 31 |
| 32 #include <re2/re2.h> |
| 33 |
30 #include "country_rules_aggregator.h" | 34 #include "country_rules_aggregator.h" |
| 35 #include "messages.h" |
31 #include "retriever.h" | 36 #include "retriever.h" |
| 37 #include "rule.h" |
32 #include "ruleset.h" | 38 #include "ruleset.h" |
33 #include "util/stl_util.h" | 39 #include "util/stl_util.h" |
34 | 40 |
35 namespace i18n { | 41 namespace i18n { |
36 namespace addressinput { | 42 namespace addressinput { |
37 | 43 |
38 namespace { | 44 namespace { |
39 | 45 |
| 46 // Returns true if the filter is empty (all problems allowed) or contains the |
| 47 // |field|->|problem| mapping (explicitly allowed). |
| 48 bool FilterAllows(const AddressProblemFilter& filter, |
| 49 AddressField field, |
| 50 AddressProblem::Type problem) { |
| 51 if (filter.empty()) { |
| 52 return true; |
| 53 } |
| 54 |
| 55 for (AddressProblemFilter::const_iterator it = filter.begin(); |
| 56 it != filter.end(); ++it) { |
| 57 if (it->first == field && it->second == problem) { |
| 58 return true; |
| 59 } |
| 60 } |
| 61 |
| 62 return false; |
| 63 } |
| 64 |
40 // Validates AddressData structure. | 65 // Validates AddressData structure. |
41 class AddressValidatorImpl : public AddressValidator { | 66 class AddressValidatorImpl : public AddressValidator { |
42 public: | 67 public: |
43 // Takes ownership of |downloader| and |storage|. Does not take ownership of | 68 // Takes ownership of |downloader| and |storage|. Does not take ownership of |
44 // |load_rules_delegate|. | 69 // |load_rules_delegate|. |
45 AddressValidatorImpl(scoped_ptr<const Downloader> downloader, | 70 AddressValidatorImpl(scoped_ptr<const Downloader> downloader, |
46 scoped_ptr<Storage> storage, | 71 scoped_ptr<Storage> storage, |
47 LoadRulesDelegate* load_rules_delegate) | 72 LoadRulesDelegate* load_rules_delegate) |
48 : aggregator_(scoped_ptr<Retriever>(new Retriever( | 73 : aggregator_(scoped_ptr<Retriever>(new Retriever( |
49 VALIDATION_DATA_URL, | 74 VALIDATION_DATA_URL, |
(...skipping 17 matching lines...) Expand all Loading... |
67 BuildScopedPtrCallback(this, &AddressValidatorImpl::OnRulesLoaded)); | 92 BuildScopedPtrCallback(this, &AddressValidatorImpl::OnRulesLoaded)); |
68 } | 93 } |
69 } | 94 } |
70 | 95 |
71 // AddressValidator implementation. | 96 // AddressValidator implementation. |
72 virtual Status ValidateAddress( | 97 virtual Status ValidateAddress( |
73 const AddressData& address, | 98 const AddressData& address, |
74 const AddressProblemFilter& filter, | 99 const AddressProblemFilter& filter, |
75 const Localization& localization, | 100 const Localization& localization, |
76 AddressProblems* problems) const { | 101 AddressProblems* problems) const { |
77 // TODO(rouslan): Validate the address. | 102 std::map<std::string, const Ruleset*>::const_iterator ruleset_it = |
78 return RULES_UNAVAILABLE; | 103 rules_.find(address.country_code); |
| 104 if (ruleset_it == rules_.end()) { |
| 105 return loading_rules_.find(address.country_code) != loading_rules_.end() |
| 106 ? RULES_NOT_READY |
| 107 : RULES_UNAVAILABLE; |
| 108 } |
| 109 |
| 110 const Ruleset* ruleset = ruleset_it->second; |
| 111 assert(ruleset != NULL); |
| 112 const Rule& country_rule = |
| 113 ruleset->GetLanguageCodeRule(address.language_code); |
| 114 |
| 115 // Validate required fields. |
| 116 for (std::vector<AddressField>::const_iterator |
| 117 field_it = country_rule.GetRequired().begin(); |
| 118 field_it != country_rule.GetRequired().end(); |
| 119 ++field_it) { |
| 120 if (address.GetField(*field_it).empty() && |
| 121 FilterAllows( |
| 122 filter, *field_it, AddressProblem::MISSING_REQUIRED_FIELD)) { |
| 123 problems->push_back(AddressProblem( |
| 124 *field_it, |
| 125 AddressProblem::MISSING_REQUIRED_FIELD, |
| 126 localization.GetString( |
| 127 IDS_LIBADDRESSINPUT_I18N_MISSING_REQUIRED_FIELD))); |
| 128 } |
| 129 } |
| 130 |
| 131 // Validate general postal code format. A country-level rule specifies the |
| 132 // regular expression for the whole postal code. |
| 133 if (!address.postal_code.empty() && |
| 134 !country_rule.GetPostalCodeFormat().empty() && |
| 135 FilterAllows(filter, |
| 136 POSTAL_CODE, |
| 137 AddressProblem::UNRECOGNIZED_FORMAT) && |
| 138 !RE2::FullMatch( |
| 139 address.postal_code, country_rule.GetPostalCodeFormat())) { |
| 140 problems->push_back(AddressProblem( |
| 141 POSTAL_CODE, |
| 142 AddressProblem::UNRECOGNIZED_FORMAT, |
| 143 localization.GetString( |
| 144 country_rule.GetInvalidPostalCodeMessageId()))); |
| 145 } |
| 146 |
| 147 while (ruleset != NULL) { |
| 148 const Rule& rule = ruleset->GetLanguageCodeRule(address.language_code); |
| 149 |
| 150 // Validate the field values, e.g. state names in US. |
| 151 AddressField sub_field_type = |
| 152 static_cast<AddressField>(ruleset->field() + 1); |
| 153 const std::string& sub_field = address.GetField(sub_field_type); |
| 154 const std::vector<std::string>& sub_keys = rule.GetSubKeys(); |
| 155 if (!sub_field.empty() && |
| 156 !sub_keys.empty() && |
| 157 FilterAllows(filter, sub_field_type, AddressProblem::UNKNOWN_VALUE) && |
| 158 std::find(sub_keys.begin(), sub_keys.end(), sub_field) == |
| 159 sub_keys.end()) { |
| 160 problems->push_back(AddressProblem( |
| 161 sub_field_type, |
| 162 AddressProblem::UNKNOWN_VALUE, |
| 163 localization.GetString( |
| 164 country_rule.GetInvalidFieldMessageId(sub_field_type)))); |
| 165 } |
| 166 |
| 167 // Validate sub-region specific postal code format. A sub-region specifies |
| 168 // the regular expression for a prefix of the postal code. |
| 169 int match_position = -1; |
| 170 if (ruleset->field() > COUNTRY && |
| 171 !address.postal_code.empty() && |
| 172 !rule.GetPostalCodeFormat().empty() && |
| 173 FilterAllows(filter, |
| 174 POSTAL_CODE, |
| 175 AddressProblem::MISMATCHING_VALUE) && |
| 176 (!RE2::PartialMatch(address.postal_code, |
| 177 rule.GetPostalCodeFormat(), |
| 178 &match_position) || |
| 179 match_position != 0)) { |
| 180 problems->push_back(AddressProblem( |
| 181 POSTAL_CODE, |
| 182 AddressProblem::MISMATCHING_VALUE, |
| 183 localization.GetString( |
| 184 country_rule.GetInvalidPostalCodeMessageId()))); |
| 185 } |
| 186 |
| 187 ruleset = ruleset->GetSubRegionRuleset(sub_field); |
| 188 } |
| 189 |
| 190 return SUCCESS; |
79 } | 191 } |
80 | 192 |
81 private: | 193 private: |
82 // Called when CountryRulesAggregator::AggregateRules loads the |ruleset| for | 194 // Called when CountryRulesAggregator::AggregateRules loads the |ruleset| for |
83 // the |country_code|. | 195 // the |country_code|. |
84 void OnRulesLoaded(bool success, | 196 void OnRulesLoaded(bool success, |
85 const std::string& country_code, | 197 const std::string& country_code, |
86 scoped_ptr<Ruleset> ruleset) { | 198 scoped_ptr<Ruleset> ruleset) { |
87 assert(rules_.find(country_code) == rules_.end()); | 199 assert(rules_.find(country_code) == rules_.end()); |
88 loading_rules_.erase(country_code); | 200 loading_rules_.erase(country_code); |
89 if (success) { | 201 if (success) { |
| 202 assert(ruleset != NULL); |
| 203 assert(ruleset->field() == COUNTRY); |
90 rules_[country_code] = ruleset.release(); | 204 rules_[country_code] = ruleset.release(); |
91 } | 205 } |
92 if (load_rules_delegate_ != NULL) { | 206 if (load_rules_delegate_ != NULL) { |
93 load_rules_delegate_->OnAddressValidationRulesLoaded( | 207 load_rules_delegate_->OnAddressValidationRulesLoaded( |
94 country_code, success); | 208 country_code, success); |
95 } | 209 } |
96 } | 210 } |
97 | 211 |
98 // Loads the ruleset for a country code. | 212 // Loads the ruleset for a country code. |
99 CountryRulesAggregator aggregator_; | 213 CountryRulesAggregator aggregator_; |
100 | 214 |
101 // An optional delegate to be invoked when a ruleset finishes loading. | 215 // An optional delegate to be invoked when a ruleset finishes loading. |
102 LoadRulesDelegate* load_rules_delegate_; | 216 LoadRulesDelegate* load_rules_delegate_; |
103 | 217 |
104 // A set of country codes for which a ruleset is being loaded. | 218 // A set of country codes for which a ruleset is being loaded. |
105 std::set<std::string> loading_rules_; | 219 std::set<std::string> loading_rules_; |
106 | 220 |
107 // A mapping of a country code to the owned ruleset for that country code. | 221 // A mapping of a country code to the owned ruleset for that country code. |
108 std::map<std::string, Ruleset*> rules_; | 222 std::map<std::string, const Ruleset*> rules_; |
109 | 223 |
110 DISALLOW_COPY_AND_ASSIGN(AddressValidatorImpl); | 224 DISALLOW_COPY_AND_ASSIGN(AddressValidatorImpl); |
111 }; | 225 }; |
112 | 226 |
113 } // namespace | 227 } // namespace |
114 | 228 |
115 AddressValidator::~AddressValidator() {} | 229 AddressValidator::~AddressValidator() {} |
116 | 230 |
117 // static | 231 // static |
118 scoped_ptr<AddressValidator> AddressValidator::Build( | 232 scoped_ptr<AddressValidator> AddressValidator::Build( |
119 scoped_ptr<const Downloader> downloader, | 233 scoped_ptr<const Downloader> downloader, |
120 scoped_ptr<Storage> storage, | 234 scoped_ptr<Storage> storage, |
121 LoadRulesDelegate* load_rules_delegate) { | 235 LoadRulesDelegate* load_rules_delegate) { |
122 return scoped_ptr<AddressValidator>(new AddressValidatorImpl( | 236 return scoped_ptr<AddressValidator>(new AddressValidatorImpl( |
123 downloader.Pass(), storage.Pass(), load_rules_delegate)); | 237 downloader.Pass(), storage.Pass(), load_rules_delegate)); |
124 } | 238 } |
125 | 239 |
126 } // namespace addressinput | 240 } // namespace addressinput |
127 } // namespace i18n | 241 } // namespace i18n |
OLD | NEW |