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 |
deleted file mode 100644 |
index dcdeac6a47ac3145e910b56221f05b25f588f8a8..0000000000000000000000000000000000000000 |
--- a/third_party/libaddressinput/chromium/cpp/src/address_validator.cc |
+++ /dev/null |
@@ -1,599 +0,0 @@ |
-// Copyright (C) 2013 Google Inc. |
-// |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
-// you may not use this file except in compliance with the License. |
-// You may obtain a copy of the License at |
-// |
-// http://www.apache.org/licenses/LICENSE-2.0 |
-// |
-// Unless required by applicable law or agreed to in writing, software |
-// distributed under the License is distributed on an "AS IS" BASIS, |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-// See the License for the specific language governing permissions and |
-// limitations under the License. |
- |
-#include <libaddressinput/address_validator.h> |
- |
-#include <libaddressinput/address_data.h> |
-#include <libaddressinput/downloader.h> |
-#include <libaddressinput/load_rules_delegate.h> |
-#include <libaddressinput/storage.h> |
-#include <libaddressinput/util/basictypes.h> |
-#include <libaddressinput/util/scoped_ptr.h> |
- |
-#include <algorithm> |
-#include <bitset> |
-#include <cassert> |
-#include <cstddef> |
-#include <map> |
-#include <set> |
-#include <string> |
-#include <utility> |
-#include <vector> |
- |
-#include <re2/re2.h> |
- |
-#include "country_rules_aggregator.h" |
-#include "grit.h" |
-#include "grit/libaddressinput_strings.h" |
-#include "region_data_constants.h" |
-#include "retriever.h" |
-#include "rule.h" |
-#include "ruleset.h" |
-#include "util/stl_util.h" |
-#include "util/string_util.h" |
- |
-namespace i18n { |
-namespace addressinput { |
- |
-namespace { |
- |
-// A type to store a list of pointers to Ruleset objects. |
-typedef std::set<const Ruleset*> Rulesets; |
- |
-// A type to map the field in a rule to rulesets. |
-typedef std::map<Rule::IdentityField, Rulesets> IdentityFieldRulesets; |
- |
-// A type to map the field in an address to rulesets. |
-typedef std::map<AddressField, IdentityFieldRulesets> AddressFieldRulesets; |
- |
-// A set of Rule::IdentityField values that match user input. |
-typedef std::bitset<Rule::IDENTITY_FIELDS_SIZE> MatchingRuleFields; |
- |
-// Returns true if |prefix_regex| matches a prefix of |value|. For example, |
-// "(90|81)" matches a prefix of "90291". |
-bool ValueMatchesPrefixRegex(const std::string& value, |
- const std::string& prefix_regex) { |
- return RE2::FullMatch(value, "^(" + prefix_regex + ").*"); |
-} |
- |
-// 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; |
-} |
- |
-// Returns |true| if the |street_address| is empty or contains only empty |
-// strings. |
-bool IsEmptyStreetAddress(const std::vector<std::string>& street_address) { |
- for (std::vector<std::string>::const_iterator it = street_address.begin(); |
- it != street_address.end(); ++it) { |
- if (!it->empty()) { |
- return false; |
- } |
- } |
- return true; |
-} |
- |
-// Returns the ID of the string that should be displayed when the given field |
-// is invalid in the context of |country_rule|. |
-int GetInvalidFieldMessageId(const Rule& country_rule, AddressField field) { |
- switch (field) { |
- case LOCALITY: |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_LOCALITY_LABEL; |
- case DEPENDENT_LOCALITY: |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_DEPENDENT_LOCALITY_LABEL; |
- |
- case ADMIN_AREA: { |
- const std::string& admin_area_name_type = |
- country_rule.GetAdminAreaNameType(); |
- if (admin_area_name_type == "area") { |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_AREA; |
- } |
- if (admin_area_name_type == "county") { |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_COUNTY_LABEL; |
- } |
- if (admin_area_name_type == "department") { |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_DEPARTMENT; |
- } |
- if (admin_area_name_type == "district") { |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_DEPENDENT_LOCALITY_LABEL; |
- } |
- if (admin_area_name_type == "do_si") { |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_DO_SI; |
- } |
- if (admin_area_name_type == "emirate") { |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_EMIRATE; |
- } |
- if (admin_area_name_type == "island") { |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_ISLAND; |
- } |
- if (admin_area_name_type == "parish") { |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_PARISH; |
- } |
- if (admin_area_name_type == "prefecture") { |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_PREFECTURE; |
- } |
- if (admin_area_name_type == "province") { |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_PROVINCE; |
- } |
- if (admin_area_name_type == "state") { |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_STATE_LABEL; |
- } |
- return INVALID_MESSAGE_ID; |
- } |
- |
- case POSTAL_CODE: { |
- const std::string& postal_code_name_type = |
- country_rule.GetPostalCodeNameType(); |
- if (postal_code_name_type == "postal") { |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_POSTAL_CODE_LABEL; |
- } |
- if (postal_code_name_type == "zip") { |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_ZIP_CODE_LABEL; |
- } |
- return INVALID_MESSAGE_ID; |
- } |
- |
- default: |
- return IDS_LIBADDRESSINPUT_I18N_INVALID_ENTRY; |
- } |
-} |
- |
-// Collects rulesets based on whether they have a parent in the given list. |
-class ParentedRulesetCollector { |
- public: |
- // Retains a reference to both of the parameters. Does not make a copy of |
- // |parent_rulesets|. Does not take ownership of |rulesets_with_parents|. The |
- // |rulesets_with_parents| parameter should not be NULL. |
- ParentedRulesetCollector(const Rulesets& parent_rulesets, |
- Rulesets* rulesets_with_parents) |
- : parent_rulesets_(parent_rulesets), |
- rulesets_with_parents_(rulesets_with_parents) { |
- assert(rulesets_with_parents_ != NULL); |
- } |
- |
- ~ParentedRulesetCollector() {} |
- |
- // Adds |ruleset_to_test| to the |rulesets_with_parents_| collection, if the |
- // given ruleset has a parent in |parent_rulesets_|. The |ruleset_to_test| |
- // parameter should not be NULL. |
- void operator()(const Ruleset* ruleset_to_test) { |
- assert(ruleset_to_test != NULL); |
- if (parent_rulesets_.find(ruleset_to_test->parent()) != |
- parent_rulesets_.end()) { |
- rulesets_with_parents_->insert(ruleset_to_test); |
- } |
- } |
- |
- private: |
- const Rulesets& parent_rulesets_; |
- Rulesets* rulesets_with_parents_; |
-}; |
- |
-// Validates AddressData structure. |
-class AddressValidatorImpl : public AddressValidator { |
- public: |
- // Takes ownership of |downloader| and |storage|. Does not take ownership of |
- // |load_rules_delegate|. |
- AddressValidatorImpl(const std::string& validation_data_url, |
- scoped_ptr<Downloader> downloader, |
- scoped_ptr<Storage> storage, |
- LoadRulesDelegate* load_rules_delegate) |
- : aggregator_(scoped_ptr<Retriever>(new Retriever( |
- validation_data_url, |
- downloader.Pass(), |
- storage.Pass()))), |
- load_rules_delegate_(load_rules_delegate), |
- loading_rules_(), |
- rules_() {} |
- |
- virtual ~AddressValidatorImpl() { |
- STLDeleteValues(&rules_); |
- } |
- |
- // AddressValidator implementation. |
- virtual void LoadRules(const std::string& country_code) { |
- if (rules_.find(country_code) == rules_.end() && |
- loading_rules_.find(country_code) == loading_rules_.end()) { |
- loading_rules_.insert(country_code); |
- aggregator_.AggregateRules( |
- country_code, |
- BuildScopedPtrCallback(this, &AddressValidatorImpl::OnRulesLoaded)); |
- } |
- } |
- |
- // AddressValidator implementation. |
- virtual Status ValidateAddress( |
- const AddressData& address, |
- const AddressProblemFilter& filter, |
- AddressProblems* problems) const { |
- std::map<std::string, Ruleset*>::const_iterator ruleset_it = |
- rules_.find(address.region_code); |
- |
- // We can still validate the required fields even if the full ruleset isn't |
- // ready. |
- if (ruleset_it == rules_.end()) { |
- if (problems != NULL) { |
- Rule rule; |
- rule.CopyFrom(Rule::GetDefault()); |
- if (rule.ParseSerializedRule( |
- RegionDataConstants::GetRegionData(address.region_code))) { |
- EnforceRequiredFields(rule, address, filter, problems); |
- } |
- } |
- |
- return loading_rules_.find(address.region_code) != loading_rules_.end() |
- ? RULES_NOT_READY |
- : RULES_UNAVAILABLE; |
- } |
- |
- if (problems == NULL) { |
- return SUCCESS; |
- } |
- |
- const Ruleset* ruleset = ruleset_it->second; |
- assert(ruleset != NULL); |
- const Rule& country_rule = |
- ruleset->GetLanguageCodeRule(address.language_code); |
- EnforceRequiredFields(country_rule, address, filter, problems); |
- |
- // 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, |
- GetInvalidFieldMessageId(country_rule, POSTAL_CODE))); |
- } |
- |
- 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); |
- std::string sub_key; |
- const std::string& user_input = address.GetFieldValue(sub_field_type); |
- if (!user_input.empty() && |
- FilterAllows(filter, sub_field_type, AddressProblem::UNKNOWN_VALUE) && |
- !rule.CanonicalizeSubKey(user_input, false, &sub_key)) { |
- problems->push_back(AddressProblem( |
- sub_field_type, |
- AddressProblem::UNKNOWN_VALUE, |
- GetInvalidFieldMessageId(country_rule, sub_field_type))); |
- } |
- |
- // Validate sub-region specific postal code format. A sub-region specifies |
- // the regular expression for a prefix of the postal code. |
- if (ruleset->field() > COUNTRY && |
- !address.postal_code.empty() && |
- !rule.GetPostalCodeFormat().empty() && |
- FilterAllows(filter, |
- POSTAL_CODE, |
- AddressProblem::MISMATCHING_VALUE) && |
- !ValueMatchesPrefixRegex( |
- address.postal_code, rule.GetPostalCodeFormat())) { |
- problems->push_back(AddressProblem( |
- POSTAL_CODE, |
- AddressProblem::MISMATCHING_VALUE, |
- GetInvalidFieldMessageId(country_rule, POSTAL_CODE))); |
- } |
- |
- ruleset = ruleset->GetSubRegionRuleset(sub_key); |
- } |
- |
- return SUCCESS; |
- } |
- |
- // AddressValidator implementation. |
- virtual Status GetSuggestions(const AddressData& user_input, |
- AddressField focused_field, |
- size_t suggestions_limit, |
- std::vector<AddressData>* suggestions) const { |
- std::map<std::string, Ruleset*>::const_iterator ruleset_it = |
- rules_.find(user_input.region_code); |
- |
- if (ruleset_it == rules_.end()) { |
- return |
- loading_rules_.find(user_input.region_code) != loading_rules_.end() |
- ? RULES_NOT_READY |
- : RULES_UNAVAILABLE; |
- } |
- |
- if (suggestions == NULL) { |
- return SUCCESS; |
- } |
- suggestions->clear(); |
- |
- assert(ruleset_it->second != NULL); |
- |
- // Do not suggest anything if the user is typing in the field for which |
- // there's no validation data. |
- if (focused_field != POSTAL_CODE && |
- (focused_field < ADMIN_AREA || focused_field > DEPENDENT_LOCALITY)) { |
- return SUCCESS; |
- } |
- |
- // Do not suggest anything if the user input is empty. |
- if (user_input.GetFieldValue(focused_field).empty()) { |
- return SUCCESS; |
- } |
- |
- const Ruleset& country_ruleset = *ruleset_it->second; |
- const Rule& country_rule = |
- country_ruleset.GetLanguageCodeRule(user_input.language_code); |
- |
- // Do not suggest anything if the user is typing the postal code that is not |
- // valid for the country. |
- if (!user_input.postal_code.empty() && |
- focused_field == POSTAL_CODE && |
- !country_rule.GetPostalCodeFormat().empty() && |
- !ValueMatchesPrefixRegex( |
- user_input.postal_code, country_rule.GetPostalCodeFormat())) { |
- return SUCCESS; |
- } |
- |
- // Initialize the prefix search index lazily. |
- if (!ruleset_it->second->prefix_search_index_ready()) { |
- ruleset_it->second->BuildPrefixSearchIndex(); |
- } |
- |
- if (focused_field != POSTAL_CODE && |
- focused_field > country_ruleset.deepest_ruleset_level()) { |
- return SUCCESS; |
- } |
- |
- // Determine the most specific address field that can be suggested. |
- AddressField suggestion_field = focused_field != POSTAL_CODE |
- ? focused_field : DEPENDENT_LOCALITY; |
- if (suggestion_field > country_ruleset.deepest_ruleset_level()) { |
- suggestion_field = country_ruleset.deepest_ruleset_level(); |
- } |
- if (focused_field != POSTAL_CODE) { |
- while (user_input.GetFieldValue(suggestion_field).empty() && |
- suggestion_field > ADMIN_AREA) { |
- suggestion_field = static_cast<AddressField>(suggestion_field - 1); |
- } |
- } |
- |
- // Find all rulesets that match user input. |
- AddressFieldRulesets rulesets; |
- for (int i = ADMIN_AREA; i <= suggestion_field; ++i) { |
- for (int j = Rule::KEY; j <= Rule::LATIN_NAME; ++j) { |
- AddressField address_field = static_cast<AddressField>(i); |
- Rule::IdentityField rule_field = static_cast<Rule::IdentityField>(j); |
- |
- // Find all rulesets at |address_field| level whose |rule_field| starts |
- // with user input value. |
- country_ruleset.FindRulesetsByPrefix( |
- user_input.language_code, address_field, rule_field, |
- user_input.GetFieldValue(address_field), |
- &rulesets[address_field][rule_field]); |
- |
- // Filter out the rulesets whose parents do not match the user input. |
- if (address_field > ADMIN_AREA) { |
- AddressField parent_field = |
- static_cast<AddressField>(address_field - 1); |
- Rulesets rulesets_with_parents; |
- std::for_each( |
- rulesets[address_field][rule_field].begin(), |
- rulesets[address_field][rule_field].end(), |
- ParentedRulesetCollector(rulesets[parent_field][rule_field], |
- &rulesets_with_parents)); |
- rulesets[address_field][rule_field].swap(rulesets_with_parents); |
- } |
- } |
- } |
- |
- // Determine the fields in the rules that match the user input. This |
- // operation converts a map of Rule::IdentityField value -> Ruleset into a |
- // map of Ruleset -> Rule::IdentityField bitset. |
- std::map<const Ruleset*, MatchingRuleFields> suggestion_rulesets; |
- for (IdentityFieldRulesets::const_iterator rule_field_it = |
- rulesets[suggestion_field].begin(); |
- rule_field_it != rulesets[suggestion_field].end(); |
- ++rule_field_it) { |
- const Rule::IdentityField rule_identity_field = rule_field_it->first; |
- for (Rulesets::const_iterator ruleset_it = rule_field_it->second.begin(); |
- ruleset_it != rule_field_it->second.end(); |
- ++ruleset_it) { |
- suggestion_rulesets[*ruleset_it].set(rule_identity_field); |
- } |
- } |
- |
- // Generate suggestions based on the rulesets. Use a Rule::IdentityField |
- // from the bitset to generate address field values. |
- for (std::map<const Ruleset*, MatchingRuleFields>::const_iterator |
- suggestion_it = suggestion_rulesets.begin(); |
- suggestion_it != suggestion_rulesets.end(); |
- ++suggestion_it) { |
- const Ruleset& ruleset = *suggestion_it->first; |
- const Rule& rule = ruleset.GetLanguageCodeRule(user_input.language_code); |
- const MatchingRuleFields& matching_rule_fields = suggestion_it->second; |
- |
- // Do not suggest this region if the postal code in user input does not |
- // match it. |
- if (!user_input.postal_code.empty() && |
- !rule.GetPostalCodeFormat().empty() && |
- !ValueMatchesPrefixRegex( |
- user_input.postal_code, rule.GetPostalCodeFormat())) { |
- continue; |
- } |
- |
- // Do not add more suggestions than |suggestions_limit|. |
- if (suggestions->size() >= suggestions_limit) { |
- suggestions->clear(); |
- return SUCCESS; |
- } |
- |
- // If the user's language is not one of the supported languages of a |
- // country that has latinized names for its regions, then prefer to |
- // suggest the latinized region names. If the user types in local script |
- // instead, then the local script names will be suggested. |
- Rule::IdentityField rule_field = Rule::KEY; |
- if (!country_rule.GetLanguage().empty() && |
- country_rule.GetLanguage() != user_input.language_code && |
- !rule.GetLatinName().empty() && |
- matching_rule_fields.test(Rule::LATIN_NAME)) { |
- rule_field = Rule::LATIN_NAME; |
- } else if (matching_rule_fields.test(Rule::KEY)) { |
- rule_field = Rule::KEY; |
- } else if (matching_rule_fields.test(Rule::NAME)) { |
- rule_field = Rule::NAME; |
- } else if (matching_rule_fields.test(Rule::LATIN_NAME)) { |
- rule_field = Rule::LATIN_NAME; |
- } else { |
- assert(false); |
- } |
- |
- AddressData suggestion; |
- suggestion.region_code = user_input.region_code; |
- suggestion.postal_code = user_input.postal_code; |
- |
- // Traverse the tree of rulesets from the most specific |ruleset| to the |
- // country-wide "root" of the tree. Use the region names found at each of |
- // the levels of the ruleset tree to build the |suggestion|. |
- for (const Ruleset* suggestion_ruleset = &ruleset; |
- suggestion_ruleset->parent() != NULL; |
- suggestion_ruleset = suggestion_ruleset->parent()) { |
- const Rule& suggestion_rule = |
- suggestion_ruleset->GetLanguageCodeRule(user_input.language_code); |
- suggestion.SetFieldValue(suggestion_ruleset->field(), |
- suggestion_rule.GetIdentityField(rule_field)); |
- } |
- |
- suggestions->push_back(suggestion); |
- } |
- |
- return SUCCESS; |
- } |
- |
- // AddressValidator implementation. |
- virtual bool CanonicalizeAdministrativeArea(AddressData* address_data) const { |
- std::map<std::string, Ruleset*>::const_iterator ruleset_it = |
- rules_.find(address_data->region_code); |
- if (ruleset_it == rules_.end()) { |
- return false; |
- } |
- const Rule& rule = |
- ruleset_it->second->GetLanguageCodeRule(address_data->language_code); |
- |
- return rule.CanonicalizeSubKey(address_data->administrative_area, |
- true, // Keep input latin. |
- &address_data->administrative_area); |
- } |
- |
- private: |
- // Called when CountryRulesAggregator::AggregateRules loads the |ruleset| for |
- // the |country_code|. |
- void OnRulesLoaded(bool success, |
- const std::string& country_code, |
- scoped_ptr<Ruleset> ruleset) { |
- 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) { |
- load_rules_delegate_->OnAddressValidationRulesLoaded( |
- country_code, success); |
- } |
- } |
- |
- // Adds problems for just the required fields portion of |country_rule|. |
- void EnforceRequiredFields(const Rule& country_rule, |
- const AddressData& address, |
- const AddressProblemFilter& filter, |
- AddressProblems* problems) const { |
- assert(problems != NULL); |
- for (std::vector<AddressField>::const_iterator |
- field_it = country_rule.GetRequired().begin(); |
- field_it != country_rule.GetRequired().end(); |
- ++field_it) { |
- bool field_empty = *field_it != STREET_ADDRESS |
- ? address.GetFieldValue(*field_it).empty() |
- : IsEmptyStreetAddress(address.address_line); |
- if (field_empty && |
- FilterAllows( |
- filter, *field_it, AddressProblem::MISSING_REQUIRED_FIELD)) { |
- problems->push_back(AddressProblem( |
- *field_it, |
- AddressProblem::MISSING_REQUIRED_FIELD, |
- IDS_LIBADDRESSINPUT_I18N_MISSING_REQUIRED_FIELD)); |
- } |
- } |
- } |
- |
- // Loads the ruleset for a country code. |
- CountryRulesAggregator aggregator_; |
- |
- // An optional delegate to be invoked when a ruleset finishes loading. |
- LoadRulesDelegate* load_rules_delegate_; |
- |
- // A set of country codes for which a ruleset is being loaded. |
- std::set<std::string> loading_rules_; |
- |
- // A mapping of a country code to the owned ruleset for that country code. |
- std::map<std::string, Ruleset*> rules_; |
- |
- DISALLOW_COPY_AND_ASSIGN(AddressValidatorImpl); |
-}; |
- |
-} // namespace |
- |
-AddressValidator::~AddressValidator() {} |
- |
-// static |
-scoped_ptr<AddressValidator> AddressValidator::Build( |
- scoped_ptr<Downloader> downloader, |
- scoped_ptr<Storage> storage, |
- LoadRulesDelegate* load_rules_delegate) { |
- return scoped_ptr<AddressValidator>(new AddressValidatorImpl( |
- VALIDATION_DATA_URL, downloader.Pass(), storage.Pass(), |
- load_rules_delegate)); |
-} |
- |
-scoped_ptr<AddressValidator> BuildAddressValidatorForTesting( |
- const std::string& validation_data_url, |
- scoped_ptr<Downloader> downloader, |
- scoped_ptr<Storage> storage, |
- LoadRulesDelegate* load_rules_delegate) { |
- return scoped_ptr<AddressValidator>(new AddressValidatorImpl( |
- validation_data_url, downloader.Pass(), storage.Pass(), |
- load_rules_delegate)); |
-} |
- |
-} // namespace addressinput |
-} // namespace i18n |