Chromium Code Reviews| Index: third_party/libaddressinput/chromium/cpp/src/address_validator.cc |
| diff --git a/third_party/libaddressinput/chromium/cpp/src/address_validator.cc b/third_party/libaddressinput/chromium/cpp/src/address_validator.cc |
| index ba48487649b67e35119199e97e44c89a50f9abf9..c7bf3ce55fdfafb082b3cef91940f1c11669b505 100644 |
| --- a/third_party/libaddressinput/chromium/cpp/src/address_validator.cc |
| +++ b/third_party/libaddressinput/chromium/cpp/src/address_validator.cc |
| @@ -14,6 +14,7 @@ |
| #include <libaddressinput/address_validator.h> |
| +#include <libaddressinput/address_data.h> |
| #include <libaddressinput/downloader.h> |
| #include <libaddressinput/load_rules_delegate.h> |
| #include <libaddressinput/localization.h> |
| @@ -21,14 +22,19 @@ |
| #include <libaddressinput/util/basictypes.h> |
| #include <libaddressinput/util/scoped_ptr.h> |
| +#include <algorithm> |
| #include <cassert> |
| #include <cstddef> |
| #include <map> |
| #include <set> |
| #include <string> |
| +#include <re2/re2.h> |
| + |
| #include "country_rules_aggregator.h" |
| +#include "messages.h" |
| #include "retriever.h" |
| +#include "rule.h" |
| #include "ruleset.h" |
| #include "util/stl_util.h" |
| @@ -37,6 +43,25 @@ namespace addressinput { |
| namespace { |
| +// Returns true if the filter is empty (all problems allowed) or contains the |
| +// |field|->|problem| mapping (explicitly allowed). |
| +bool FilterAllows(const AddressProblemFilter& filter, |
| + AddressField field, |
| + AddressProblem::Type problem) { |
| + if (filter.empty()) { |
| + return true; |
| + } |
| + |
| + for (AddressProblemFilter::const_iterator it = filter.begin(); |
| + it != filter.end(); ++it) { |
| + if (it->first == field && it->second == problem) { |
| + return true; |
| + } |
| + } |
| + |
| + return false; |
| +} |
| + |
| // Validates AddressData structure. |
| class AddressValidatorImpl : public AddressValidator { |
| public: |
| @@ -74,8 +99,95 @@ class AddressValidatorImpl : public AddressValidator { |
| const AddressProblemFilter& filter, |
| const Localization& localization, |
| AddressProblems* problems) const { |
| - // TODO(rouslan): Validate the address. |
| - return RULES_UNAVAILABLE; |
| + std::map<std::string, Ruleset*>::const_iterator ruleset_it = |
| + rules_.find(address.country_code); |
| + if (ruleset_it == rules_.end()) { |
| + return loading_rules_.find(address.country_code) != loading_rules_.end() |
| + ? RULES_NOT_READY |
| + : RULES_UNAVAILABLE; |
| + } |
| + |
| + Ruleset* ruleset = ruleset_it->second; |
|
Evan Stade
2014/01/09 21:58:46
constify?
please use gerrit instead
2014/01/09 22:10:53
Done.
|
| + assert(ruleset != NULL); |
| + const Rule& country_rule = |
| + ruleset->GetLanguageCodeRule(address.language_code); |
| + |
| + // Validate required fields. |
| + for (std::vector<AddressField>::const_iterator |
| + field_it = country_rule.GetRequired().begin(); |
| + field_it != country_rule.GetRequired().end(); |
| + ++field_it) { |
| + if (address.GetField(*field_it).empty() && |
| + FilterAllows( |
| + filter, *field_it, AddressProblem::MISSING_REQUIRED_FIELD)) { |
| + problems->push_back(AddressProblem( |
| + *field_it, |
| + AddressProblem::MISSING_REQUIRED_FIELD, |
| + localization.GetString( |
| + IDS_LIBADDRESSINPUT_I18N_MISSING_REQUIRED_FIELD))); |
| + } |
| + } |
| + |
| + // Validate general postal code format. A country-level rule specifies the |
| + // regular expression for the whole postal code. |
| + if (!address.postal_code.empty() && |
| + !country_rule.GetPostalCodeFormat().empty() && |
| + FilterAllows(filter, |
| + POSTAL_CODE, |
| + AddressProblem::UNRECOGNIZED_FORMAT) && |
| + !RE2::FullMatch( |
| + address.postal_code, country_rule.GetPostalCodeFormat())) { |
| + problems->push_back(AddressProblem( |
| + POSTAL_CODE, |
| + AddressProblem::UNRECOGNIZED_FORMAT, |
| + localization.GetString( |
| + country_rule.GetInvalidPostalCodeMessageId()))); |
| + } |
| + |
| + while (ruleset != NULL) { |
| + const Rule& rule = ruleset->GetLanguageCodeRule(address.language_code); |
| + |
| + // Validate the field values, e.g. state names in US. |
| + AddressField sub_field_type = |
| + static_cast<AddressField>(ruleset->field() + 1); |
| + const std::string& sub_field = address.GetField(sub_field_type); |
| + const std::vector<std::string>& sub_keys = rule.GetSubKeys(); |
| + if (!sub_field.empty() && |
| + !sub_keys.empty() && |
| + FilterAllows(filter, sub_field_type, AddressProblem::UNKNOWN_VALUE) && |
| + std::find(sub_keys.begin(), sub_keys.end(), sub_field) == |
| + sub_keys.end()) { |
| + problems->push_back(AddressProblem( |
| + sub_field_type, |
| + AddressProblem::UNKNOWN_VALUE, |
| + localization.GetString( |
| + country_rule.GetInvalidFieldMessageId(sub_field_type)))); |
| + } |
| + |
| + // Validate sub-region specific postal code format. A sub-region specifies |
| + // the regular expression for a prefix of the postal code. |
| + int match_position = -1; |
| + if (ruleset->field() > COUNTRY && |
| + !address.postal_code.empty() && |
| + !rule.GetPostalCodeFormat().empty() && |
| + FilterAllows(filter, |
| + POSTAL_CODE, |
| + AddressProblem::MISMATCHING_VALUE) && |
| + (!RE2::PartialMatch(address.postal_code, |
| + rule.GetPostalCodeFormat(), |
| + &match_position) || |
| + match_position != 0)) { |
| + problems->push_back(AddressProblem( |
| + POSTAL_CODE, |
| + AddressProblem::MISMATCHING_VALUE, |
| + localization.GetString( |
| + country_rule.GetInvalidPostalCodeMessageId()))); |
| + } |
| + |
| + ruleset = ruleset->GetSubRegionRuleset(sub_field); |
| + } |
| + |
| + return SUCCESS; |
| } |
| private: |
| @@ -87,6 +199,8 @@ class AddressValidatorImpl : public AddressValidator { |
| assert(rules_.find(country_code) == rules_.end()); |
| loading_rules_.erase(country_code); |
| if (success) { |
| + assert(ruleset != NULL); |
| + assert(ruleset->field() == COUNTRY); |
| rules_[country_code] = ruleset.release(); |
| } |
| if (load_rules_delegate_ != NULL) { |