Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / libaddressinput / src / cpp / src / validation_task.cc
1 // Copyright (C) 2014 Google Inc.
2 //
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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14
15 #include "validation_task.h"
16
17 #include <libaddressinput/address_data.h>
18 #include <libaddressinput/address_field.h>
19 #include <libaddressinput/address_metadata.h>
20 #include <libaddressinput/address_problem.h>
21 #include <libaddressinput/address_validator.h>
22 #include <libaddressinput/callback.h>
23 #include <libaddressinput/supplier.h>
24 #include <libaddressinput/util/basictypes.h>
25
26 #include <algorithm>
27 #include <cassert>
28 #include <cstddef>
29 #include <string>
30 #include <utility>
31 #include <vector>
32
33 #include <re2/re2.h>
34
35 #include "lookup_key.h"
36 #include "post_box_matchers.h"
37 #include "rule.h"
38 #include "util/re2ptr.h"
39
40 namespace i18n {
41 namespace addressinput {
42
43 ValidationTask::ValidationTask(const AddressData& address,
44                                bool allow_postal,
45                                bool require_name,
46                                const FieldProblemMap* filter,
47                                FieldProblemMap* problems,
48                                const AddressValidator::Callback& validated)
49     : address_(address),
50       allow_postal_(allow_postal),
51       require_name_(require_name),
52       filter_(filter),
53       problems_(problems),
54       validated_(validated),
55       supplied_(BuildCallback(this, &ValidationTask::Validate)),
56       lookup_key_(new LookupKey) {
57   assert(problems_ != NULL);
58   assert(supplied_ != NULL);
59   assert(lookup_key_ != NULL);
60 }
61
62 ValidationTask::~ValidationTask() {
63 }
64
65 void ValidationTask::Run(Supplier* supplier) const {
66   assert(supplier != NULL);
67   problems_->clear();
68   lookup_key_->FromAddress(address_);
69   supplier->Supply(*lookup_key_, *supplied_);
70 }
71
72 void ValidationTask::Validate(bool success,
73                               const LookupKey& lookup_key,
74                               const Supplier::RuleHierarchy& hierarchy) {
75   assert(&lookup_key == lookup_key_.get());  // Sanity check.
76
77   if (success) {
78     if (address_.IsFieldEmpty(COUNTRY)) {
79       ReportProblemMaybe(COUNTRY, MISSING_REQUIRED_FIELD);
80     } else if (hierarchy.rule[0] == NULL) {
81       ReportProblemMaybe(COUNTRY, UNKNOWN_VALUE);
82     } else {
83       // Checks which use statically linked metadata.
84       const std::string& region_code = address_.region_code;
85       CheckUnexpectedField(region_code);
86       CheckMissingRequiredField(region_code);
87
88       // Checks which use data from the metadata server. Note that
89       // CheckPostalCodeFormatAndValue assumes CheckUnexpectedField has already
90       // been called.
91       CheckUnknownValue(hierarchy);
92       CheckPostalCodeFormatAndValue(hierarchy);
93       CheckUsesPoBox(hierarchy);
94     }
95   }
96
97   validated_(success, address_, *problems_);
98   delete this;
99 }
100
101 // A field will return an UNEXPECTED_FIELD problem type if the current value of
102 // that field is not empty and the field should not be used by that region.
103 void ValidationTask::CheckUnexpectedField(
104     const std::string& region_code) const {
105   static const AddressField kFields[] = {
106     // COUNTRY is never unexpected.
107     ADMIN_AREA,
108     LOCALITY,
109     DEPENDENT_LOCALITY,
110     SORTING_CODE,
111     POSTAL_CODE,
112     STREET_ADDRESS,
113     ORGANIZATION,
114     RECIPIENT
115   };
116
117   for (size_t i = 0; i < arraysize(kFields); ++i) {
118     AddressField field = kFields[i];
119     if (!address_.IsFieldEmpty(field) && !IsFieldUsed(field, region_code)) {
120       ReportProblemMaybe(field, UNEXPECTED_FIELD);
121     }
122   }
123 }
124
125 // A field will return an MISSING_REQUIRED_FIELD problem type if the current
126 // value of that field is empty and the field is required by that region.
127 void ValidationTask::CheckMissingRequiredField(
128     const std::string& region_code) const {
129   static const AddressField kFields[] = {
130     // COUNTRY is assumed to have already been checked.
131     ADMIN_AREA,
132     LOCALITY,
133     DEPENDENT_LOCALITY,
134     SORTING_CODE,
135     POSTAL_CODE,
136     STREET_ADDRESS
137     // ORGANIZATION is never required.
138     // RECIPIENT is handled separately.
139   };
140
141   for (size_t i = 0; i < arraysize(kFields); ++i) {
142     AddressField field = kFields[i];
143     if (address_.IsFieldEmpty(field) && IsFieldRequired(field, region_code)) {
144       ReportProblemMaybe(field, MISSING_REQUIRED_FIELD);
145     }
146   }
147
148   if (require_name_ && address_.IsFieldEmpty(RECIPIENT)) {
149     ReportProblemMaybe(RECIPIENT, MISSING_REQUIRED_FIELD);
150   }
151 }
152
153 // A field is UNKNOWN_VALUE if the metadata contains a list of possible values
154 // for the field and the address data server could not match the current value
155 // of that field to one of those possible values, therefore returning NULL.
156 void ValidationTask::CheckUnknownValue(
157     const Supplier::RuleHierarchy& hierarchy) const {
158   for (size_t depth = 1; depth < arraysize(LookupKey::kHierarchy); ++depth) {
159     AddressField field = LookupKey::kHierarchy[depth];
160     if (!(address_.IsFieldEmpty(field) ||
161           hierarchy.rule[depth - 1] == NULL ||
162           hierarchy.rule[depth - 1]->GetSubKeys().empty() ||
163           hierarchy.rule[depth] != NULL)) {
164       ReportProblemMaybe(field, UNKNOWN_VALUE);
165     }
166   }
167 }
168
169 // Note that it is assumed that CheckUnexpectedField has already been called.
170 void ValidationTask::CheckPostalCodeFormatAndValue(
171     const Supplier::RuleHierarchy& hierarchy) const {
172   assert(hierarchy.rule[0] != NULL);
173   const Rule& country_rule = *hierarchy.rule[0];
174
175   if (!(ShouldReport(POSTAL_CODE, INVALID_FORMAT) ||
176         ShouldReport(POSTAL_CODE, MISMATCHING_VALUE))) {
177     return;
178   }
179
180   if (address_.IsFieldEmpty(POSTAL_CODE)) {
181     return;
182   } else if (std::find(problems_->begin(), problems_->end(),
183                        FieldProblemMap::value_type(POSTAL_CODE,
184                                                    UNEXPECTED_FIELD))
185              != problems_->end()) {
186     return;  // Problem already reported.
187   }
188
189   // Validate general postal code format. A country-level rule specifies the
190   // regular expression for the whole postal code.
191   const RE2ptr* format_ptr = country_rule.GetPostalCodeMatcher();
192   if (format_ptr != NULL &&
193       !RE2::FullMatch(address_.postal_code, *format_ptr->ptr) &&
194       ShouldReport(POSTAL_CODE, INVALID_FORMAT)) {
195     ReportProblem(POSTAL_CODE, INVALID_FORMAT);
196     return;
197   }
198
199   if (!ShouldReport(POSTAL_CODE, MISMATCHING_VALUE)) {
200     return;
201   }
202
203   for (size_t depth = arraysize(LookupKey::kHierarchy) - 1;
204        depth > 0; --depth) {
205     if (hierarchy.rule[depth] != NULL) {
206       // Validate sub-region specific postal code format. A sub-region specifies
207       // the regular expression for a prefix of the postal code.
208       const RE2ptr* prefix_ptr = hierarchy.rule[depth]->GetPostalCodeMatcher();
209       if (prefix_ptr != NULL) {
210         if (!RE2::PartialMatch(address_.postal_code, *prefix_ptr->ptr)) {
211           ReportProblem(POSTAL_CODE, MISMATCHING_VALUE);
212         }
213         return;
214       }
215     }
216   }
217 }
218
219 void ValidationTask::CheckUsesPoBox(
220     const Supplier::RuleHierarchy& hierarchy) const {
221   assert(hierarchy.rule[0] != NULL);
222   const Rule& country_rule = *hierarchy.rule[0];
223
224   if (allow_postal_ ||
225       !ShouldReport(STREET_ADDRESS, USES_P_O_BOX) ||
226       address_.IsFieldEmpty(STREET_ADDRESS)) {
227     return;
228   }
229
230   std::vector<const RE2ptr*> matchers =
231       PostBoxMatchers::GetMatchers(country_rule);
232   for (std::vector<std::string>::const_iterator
233        line = address_.address_line.begin();
234        line != address_.address_line.end(); ++line) {
235     for (std::vector<const RE2ptr*>::const_iterator
236          matcher = matchers.begin();
237          matcher != matchers.end(); ++matcher) {
238       if (RE2::PartialMatch(*line, *(*matcher)->ptr)) {
239         ReportProblem(STREET_ADDRESS, USES_P_O_BOX);
240         return;
241       }
242     }
243   }
244 }
245
246 void ValidationTask::ReportProblem(AddressField field,
247                                    AddressProblem problem) const {
248   problems_->insert(std::make_pair(field, problem));
249 }
250
251 void ValidationTask::ReportProblemMaybe(AddressField field,
252                                         AddressProblem problem) const {
253   if (ShouldReport(field, problem)) {
254     ReportProblem(field, problem);
255   }
256 }
257
258 bool ValidationTask::ShouldReport(AddressField field,
259                                   AddressProblem problem) const {
260   return filter_ == NULL || filter_->empty() ||
261          std::find(filter_->begin(),
262                    filter_->end(),
263                    FieldProblemMap::value_type(field, problem)) !=
264              filter_->end();
265 }
266
267 }  // namespace addressinput
268 }  // namespace i18n