Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: android_webview/native/address_parser_internal.cc

Issue 2803163002: Move address parser and prefixes to android_webview/. (Closed)
Patch Set: Bring back ContentViewStatics import Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "android_webview/native/address_parser_internal.h"
6
7 #include <bitset>
8
9 #include "base/logging.h"
10 #include "base/macros.h"
11 #include "base/strings/string_util.h"
12
13 namespace {
14
15 // Number of digits for a valid zip code.
16 const size_t kZipDigits = 5;
17
18 // Number of digits for a valid zip code in the Zip Plus 4 format.
19 const size_t kZipPlus4Digits = 9;
20
21 // Maximum number of digits of a house number, including possible hyphens.
22 const size_t kMaxHouseDigits = 5;
23
24 base::char16 SafePreviousChar(const base::string16::const_iterator& it,
25 const base::string16::const_iterator& begin) {
26 if (it == begin)
27 return ' ';
28 return *(it - 1);
29 }
30
31 base::char16 SafeNextChar(const base::string16::const_iterator& it,
32 const base::string16::const_iterator& end) {
33 if (it == end)
34 return ' ';
35 return *(it + 1);
36 }
37
38 bool WordLowerCaseEqualsASCII(base::string16::const_iterator word_begin,
39 base::string16::const_iterator word_end,
40 const char* ascii_to_match) {
41 for (base::string16::const_iterator it = word_begin; it != word_end;
42 ++it, ++ascii_to_match) {
43 if (!*ascii_to_match || base::ToLowerASCII(*it) != *ascii_to_match)
44 return false;
45 }
46 return *ascii_to_match == 0 || *ascii_to_match == ' ';
47 }
48
49 bool LowerCaseEqualsASCIIWithPlural(base::string16::const_iterator word_begin,
50 base::string16::const_iterator word_end,
51 const char* ascii_to_match,
52 bool allow_plural) {
53 for (base::string16::const_iterator it = word_begin; it != word_end;
54 ++it, ++ascii_to_match) {
55 if (!*ascii_to_match && allow_plural && *it == 's' && it + 1 == word_end)
56 return true;
57
58 if (!*ascii_to_match || base::ToLowerASCII(*it) != *ascii_to_match)
59 return false;
60 }
61 return *ascii_to_match == 0;
62 }
63
64 } // anonymous namespace
65
66 namespace android_webview {
67
68 namespace address_parser {
69
70 namespace internal {
71
72 Word::Word() {}
73
74 Word::Word(const base::string16::const_iterator& begin,
75 const base::string16::const_iterator& end)
76 : begin(begin), end(end) {
77 DCHECK(begin <= end);
78 }
79
80 Word::Word(const Word& other) = default;
81
82 HouseNumberParser::HouseNumberParser() {}
83
84 bool HouseNumberParser::IsPreDelimiter(base::char16 character) {
85 return character == ':' || IsPostDelimiter(character);
86 }
87
88 bool HouseNumberParser::IsPostDelimiter(base::char16 character) {
89 return base::IsUnicodeWhitespace(character) || strchr(",\"'", character);
90 }
91
92 void HouseNumberParser::RestartOnNextDelimiter() {
93 ResetState();
94 for (; it_ != end_ && !IsPreDelimiter(*it_); ++it_) {
95 }
96 }
97
98 void HouseNumberParser::AcceptChars(size_t num_chars) {
99 size_t offset =
100 std::min(static_cast<size_t>(std::distance(it_, end_)), num_chars);
101 it_ += offset;
102 result_chars_ += offset;
103 }
104
105 void HouseNumberParser::SkipChars(size_t num_chars) {
106 it_ += std::min(static_cast<size_t>(std::distance(it_, end_)), num_chars);
107 }
108
109 void HouseNumberParser::ResetState() {
110 num_digits_ = 0;
111 result_chars_ = 0;
112 }
113
114 bool HouseNumberParser::CheckFinished(Word* word) const {
115 // There should always be a number after a hyphen.
116 if (result_chars_ == 0 || SafePreviousChar(it_, begin_) == '-')
117 return false;
118
119 if (word) {
120 word->begin = it_ - result_chars_;
121 word->end = it_;
122 }
123 return true;
124 }
125
126 bool HouseNumberParser::Parse(const base::string16::const_iterator& begin,
127 const base::string16::const_iterator& end,
128 Word* word) {
129 it_ = begin_ = begin;
130 end_ = end;
131 ResetState();
132
133 // Iterations only used as a fail-safe against any buggy infinite loops.
134 size_t iterations = 0;
135 size_t max_iterations = end - begin + 1;
136 for (; it_ != end_ && iterations < max_iterations; ++iterations) {
137 // Word finished case.
138 if (IsPostDelimiter(*it_)) {
139 if (CheckFinished(word))
140 return true;
141 else if (result_chars_)
142 ResetState();
143
144 SkipChars(1);
145 continue;
146 }
147
148 // More digits. There should be no more after a letter was found.
149 if (base::IsAsciiDigit(*it_)) {
150 if (num_digits_ >= kMaxHouseDigits) {
151 RestartOnNextDelimiter();
152 } else {
153 AcceptChars(1);
154 ++num_digits_;
155 }
156 continue;
157 }
158
159 if (base::IsAsciiAlpha(*it_)) {
160 // Handle special case 'one'.
161 if (result_chars_ == 0) {
162 if (it_ + 3 <= end_ && base::LowerCaseEqualsASCII(
163 base::StringPiece16(it_, it_ + 3), "one"))
164 AcceptChars(3);
165 else
166 RestartOnNextDelimiter();
167 continue;
168 }
169
170 // There should be more than 1 character because of result_chars.
171 DCHECK_GT(result_chars_, 0U);
172 DCHECK(it_ != begin_);
173 base::char16 previous = SafePreviousChar(it_, begin_);
174 if (base::IsAsciiDigit(previous)) {
175 // Check cases like '12A'.
176 base::char16 next = SafeNextChar(it_, end_);
177 if (IsPostDelimiter(next)) {
178 AcceptChars(1);
179 continue;
180 }
181
182 // Handle cases like 12a, 1st, 2nd, 3rd, 7th.
183 if (base::IsAsciiAlpha(next)) {
184 base::char16 last_digit = previous;
185 base::char16 first_letter = base::ToLowerASCII(*it_);
186 base::char16 second_letter = base::ToLowerASCII(next);
187 bool is_teen =
188 SafePreviousChar(it_ - 1, begin_) == '1' && num_digits_ == 2;
189
190 switch (last_digit - '0') {
191 case 1:
192 if ((first_letter == 's' && second_letter == 't') ||
193 (first_letter == 't' && second_letter == 'h' && is_teen)) {
194 AcceptChars(2);
195 continue;
196 }
197 break;
198
199 case 2:
200 if ((first_letter == 'n' && second_letter == 'd') ||
201 (first_letter == 't' && second_letter == 'h' && is_teen)) {
202 AcceptChars(2);
203 continue;
204 }
205 break;
206
207 case 3:
208 if ((first_letter == 'r' && second_letter == 'd') ||
209 (first_letter == 't' && second_letter == 'h' && is_teen)) {
210 AcceptChars(2);
211 continue;
212 }
213 break;
214
215 case 0:
216 // Explicitly exclude '0th'.
217 if (num_digits_ == 1)
218 break;
219
220 case 4:
221 case 5:
222 case 6:
223 case 7:
224 case 8:
225 case 9:
226 if (first_letter == 't' && second_letter == 'h') {
227 AcceptChars(2);
228 continue;
229 }
230 break;
231
232 default:
233 NOTREACHED();
234 }
235 }
236 }
237
238 RestartOnNextDelimiter();
239 continue;
240 }
241
242 if (*it_ == '-' && num_digits_ > 0) {
243 AcceptChars(1);
244 ++num_digits_;
245 continue;
246 }
247
248 RestartOnNextDelimiter();
249 SkipChars(1);
250 }
251
252 if (iterations >= max_iterations)
253 return false;
254
255 return CheckFinished(word);
256 }
257
258 bool FindStateStartingInWord(WordList* words,
259 size_t state_first_word,
260 size_t* state_last_word,
261 String16Tokenizer* tokenizer,
262 size_t* state_index) {
263 // Bitmasks containing the allowed suffixes for 2-letter state codes.
264 static const int state_two_letter_suffix[23] = {
265 0x02060c00, // A followed by: [KLRSZ].
266 0x00000000, // B.
267 0x00084001, // C followed by: [AOT].
268 0x00000014, // D followed by: [CE].
269 0x00000000, // E.
270 0x00001800, // F followed by: [LM].
271 0x00100001, // G followed by: [AU].
272 0x00000100, // H followed by: [I].
273 0x00002809, // I followed by: [ADLN].
274 0x00000000, // J.
275 0x01040000, // K followed by: [SY].
276 0x00000001, // L followed by: [A].
277 0x000ce199, // M followed by: [ADEHINOPST].
278 0x0120129c, // N followed by: [CDEHJMVY].
279 0x00020480, // O followed by: [HKR].
280 0x00420001, // P followed by: [ARW].
281 0x00000000, // Q.
282 0x00000100, // R followed by: [I].
283 0x0000000c, // S followed by: [CD].
284 0x00802000, // T followed by: [NX].
285 0x00080000, // U followed by: [T].
286 0x00080101, // V followed by: [AIT].
287 0x01200101 // W followed by: [AIVY].
288 };
289
290 // Accumulative number of states for the 2-letter code indexed by the first.
291 static const int state_two_letter_accumulative[24] = {
292 0, 5, 5, 8, 10, 10, 12, 14, 15, 19, 19, 21,
293 22, 32, 40, 43, 46, 46, 47, 49, 51, 52, 55, 59};
294
295 // State names sorted alphabetically with their lengths.
296 // There can be more than one possible name for a same state if desired.
297 static const struct StateNameInfo {
298 const char* string;
299 char first_word_length;
300 char length;
301 char state_index; // Relative to two-character code alphabetical order.
302 } state_names[59] = {{"alabama", 7, 7, 1},
303 {"alaska", 6, 6, 0},
304 {"american samoa", 8, 14, 3},
305 {"arizona", 7, 7, 4},
306 {"arkansas", 8, 8, 2},
307 {"california", 10, 10, 5},
308 {"colorado", 8, 8, 6},
309 {"connecticut", 11, 11, 7},
310 {"delaware", 8, 8, 9},
311 {"district of columbia", 8, 20, 8},
312 {"federated states of micronesia", 9, 30, 11},
313 {"florida", 7, 7, 10},
314 {"guam", 4, 4, 13},
315 {"georgia", 7, 7, 12},
316 {"hawaii", 6, 6, 14},
317 {"idaho", 5, 5, 16},
318 {"illinois", 8, 8, 17},
319 {"indiana", 7, 7, 18},
320 {"iowa", 4, 4, 15},
321 {"kansas", 6, 6, 19},
322 {"kentucky", 8, 8, 20},
323 {"louisiana", 9, 9, 21},
324 {"maine", 5, 5, 24},
325 {"marshall islands", 8, 16, 25},
326 {"maryland", 8, 8, 23},
327 {"massachusetts", 13, 13, 22},
328 {"michigan", 8, 8, 26},
329 {"minnesota", 9, 9, 27},
330 {"mississippi", 11, 11, 30},
331 {"missouri", 8, 8, 28},
332 {"montana", 7, 7, 31},
333 {"nebraska", 8, 8, 34},
334 {"nevada", 6, 6, 38},
335 {"new hampshire", 3, 13, 35},
336 {"new jersey", 3, 10, 36},
337 {"new mexico", 3, 10, 37},
338 {"new york", 3, 8, 39},
339 {"north carolina", 5, 14, 32},
340 {"north dakota", 5, 12, 33},
341 {"northern mariana islands", 8, 24, 29},
342 {"ohio", 4, 4, 40},
343 {"oklahoma", 8, 8, 41},
344 {"oregon", 6, 6, 42},
345 {"palau", 5, 5, 45},
346 {"pennsylvania", 12, 12, 43},
347 {"puerto rico", 6, 11, 44},
348 {"rhode island", 5, 5, 46},
349 {"south carolina", 5, 14, 47},
350 {"south dakota", 5, 12, 48},
351 {"tennessee", 9, 9, 49},
352 {"texas", 5, 5, 50},
353 {"utah", 4, 4, 51},
354 {"vermont", 7, 7, 54},
355 {"virgin islands", 6, 14, 53},
356 {"virginia", 8, 8, 52},
357 {"washington", 10, 10, 55},
358 {"west virginia", 4, 13, 57},
359 {"wisconsin", 9, 9, 56},
360 {"wyoming", 7, 7, 58}};
361
362 // Accumulative number of states for sorted names indexed by the first letter.
363 // Required a different one since there are codes that don't share their
364 // first letter with the name of their state (MP = Northern Mariana Islands).
365 static const int state_names_accumulative[24] = {
366 0, 5, 5, 8, 10, 10, 12, 14, 15, 19, 19, 21,
367 22, 31, 40, 43, 46, 46, 47, 49, 51, 52, 55, 59};
368
369 DCHECK_EQ(state_names_accumulative[arraysize(state_names_accumulative) - 1],
370 static_cast<int>(arraysize(state_names)));
371
372 const Word& first_word = words->at(state_first_word);
373 int length = first_word.end - first_word.begin;
374 if (length < 2 || !base::IsAsciiAlpha(*first_word.begin))
375 return false;
376
377 // No state names start with x, y, z.
378 base::char16 first_letter = base::ToLowerASCII(*first_word.begin);
379 if (first_letter > 'w')
380 return false;
381
382 DCHECK(first_letter >= 'a');
383 int first_index = first_letter - 'a';
384
385 // Look for two-letter state names.
386 if (length == 2 && base::IsAsciiAlpha(*(first_word.begin + 1))) {
387 base::char16 second_letter = base::ToLowerASCII(*(first_word.begin + 1));
388 DCHECK(second_letter >= 'a');
389
390 int second_index = second_letter - 'a';
391 if (!(state_two_letter_suffix[first_index] & (1 << second_index)))
392 return false;
393
394 std::bitset<32> previous_suffixes =
395 state_two_letter_suffix[first_index] & ((1 << second_index) - 1);
396 *state_last_word = state_first_word;
397 *state_index =
398 state_two_letter_accumulative[first_index] + previous_suffixes.count();
399 return true;
400 }
401
402 // Look for full state names by their first letter. Discard by length.
403 for (int state = state_names_accumulative[first_index];
404 state < state_names_accumulative[first_index + 1]; ++state) {
405 if (state_names[state].first_word_length != length)
406 continue;
407
408 bool state_match = false;
409 size_t state_word = state_first_word;
410 for (int pos = 0; true;) {
411 if (!WordLowerCaseEqualsASCII(words->at(state_word).begin,
412 words->at(state_word).end,
413 &state_names[state].string[pos]))
414 break;
415
416 pos += words->at(state_word).end - words->at(state_word).begin + 1;
417 if (pos >= state_names[state].length) {
418 state_match = true;
419 break;
420 }
421
422 // Ran out of words, extract more from the tokenizer.
423 if (++state_word == words->size()) {
424 do {
425 if (!tokenizer->GetNext())
426 break;
427 } while (tokenizer->token_is_delim());
428 words->push_back(
429 Word(tokenizer->token_begin(), tokenizer->token_end()));
430 }
431 }
432
433 if (state_match) {
434 *state_last_word = state_word;
435 *state_index = state_names[state].state_index;
436 return true;
437 }
438 }
439
440 return false;
441 }
442
443 bool IsZipValid(const Word& word, size_t state_index) {
444 size_t length = word.end - word.begin;
445 if (length != kZipDigits && length != kZipPlus4Digits + 1)
446 return false;
447
448 for (base::string16::const_iterator it = word.begin; it != word.end; ++it) {
449 size_t pos = it - word.begin;
450 if (base::IsAsciiDigit(*it) || (*it == '-' && pos == kZipDigits))
451 continue;
452 return false;
453 }
454 return IsZipValidForState(word, state_index);
455 }
456
457 bool IsZipValidForState(const Word& word, size_t state_index) {
458 // List of valid zip code ranges.
459 static const struct {
460 signed char low;
461 signed char high;
462 signed char exception1;
463 signed char exception2;
464 } zip_range[] = {
465 {99, 99, -1, -1}, // AK Alaska.
466 {35, 36, -1, -1}, // AL Alabama.
467 {71, 72, -1, -1}, // AR Arkansas.
468 {96, 96, -1, -1}, // AS American Samoa.
469 {85, 86, -1, -1}, // AZ Arizona.
470 {90, 96, -1, -1}, // CA California.
471 {80, 81, -1, -1}, // CO Colorado.
472 {6, 6, -1, -1}, // CT Connecticut.
473 {20, 20, -1, -1}, // DC District of Columbia.
474 {19, 19, -1, -1}, // DE Delaware.
475 {32, 34, -1, -1}, // FL Florida.
476 {96, 96, -1, -1}, // FM Federated States of Micronesia.
477 {30, 31, -1, -1}, // GA Georgia.
478 {96, 96, -1, -1}, // GU Guam.
479 {96, 96, -1, -1}, // HI Hawaii.
480 {50, 52, -1, -1}, // IA Iowa.
481 {83, 83, -1, -1}, // ID Idaho.
482 {60, 62, -1, -1}, // IL Illinois.
483 {46, 47, -1, -1}, // IN Indiana.
484 {66, 67, 73, -1}, // KS Kansas.
485 {40, 42, -1, -1}, // KY Kentucky.
486 {70, 71, -1, -1}, // LA Louisiana.
487 {1, 2, -1, -1}, // MA Massachusetts.
488 {20, 21, -1, -1}, // MD Maryland.
489 {3, 4, -1, -1}, // ME Maine.
490 {96, 96, -1, -1}, // MH Marshall Islands.
491 {48, 49, -1, -1}, // MI Michigan.
492 {55, 56, -1, -1}, // MN Minnesota.
493 {63, 65, -1, -1}, // MO Missouri.
494 {96, 96, -1, -1}, // MP Northern Mariana Islands.
495 {38, 39, -1, -1}, // MS Mississippi.
496 {55, 56, -1, -1}, // MT Montana.
497 {27, 28, -1, -1}, // NC North Carolina.
498 {58, 58, -1, -1}, // ND North Dakota.
499 {68, 69, -1, -1}, // NE Nebraska.
500 {3, 4, -1, -1}, // NH New Hampshire.
501 {7, 8, -1, -1}, // NJ New Jersey.
502 {87, 88, 86, -1}, // NM New Mexico.
503 {88, 89, 96, -1}, // NV Nevada.
504 {10, 14, 0, 6}, // NY New York.
505 {43, 45, -1, -1}, // OH Ohio.
506 {73, 74, -1, -1}, // OK Oklahoma.
507 {97, 97, -1, -1}, // OR Oregon.
508 {15, 19, -1, -1}, // PA Pennsylvania.
509 {6, 6, 0, 9}, // PR Puerto Rico.
510 {96, 96, -1, -1}, // PW Palau.
511 {2, 2, -1, -1}, // RI Rhode Island.
512 {29, 29, -1, -1}, // SC South Carolina.
513 {57, 57, -1, -1}, // SD South Dakota.
514 {37, 38, -1, -1}, // TN Tennessee.
515 {75, 79, 87, 88}, // TX Texas.
516 {84, 84, -1, -1}, // UT Utah.
517 {22, 24, 20, -1}, // VA Virginia.
518 {6, 9, -1, -1}, // VI Virgin Islands.
519 {5, 5, -1, -1}, // VT Vermont.
520 {98, 99, -1, -1}, // WA Washington.
521 {53, 54, -1, -1}, // WI Wisconsin.
522 {24, 26, -1, -1}, // WV West Virginia.
523 {82, 83, -1, -1} // WY Wyoming.
524 };
525
526 // Zip numeric value for the first two characters.
527 DCHECK(word.begin != word.end);
528 DCHECK(base::IsAsciiDigit(*word.begin));
529 DCHECK(base::IsAsciiDigit(*(word.begin + 1)));
530 int zip_prefix = (*word.begin - '0') * 10 + (*(word.begin + 1) - '0');
531
532 if ((zip_prefix >= zip_range[state_index].low &&
533 zip_prefix <= zip_range[state_index].high) ||
534 zip_prefix == zip_range[state_index].exception1 ||
535 zip_prefix == zip_range[state_index].exception2) {
536 return true;
537 }
538 return false;
539 }
540
541 bool IsValidLocationName(const Word& word) {
542 // Supported location names sorted alphabetically and grouped by first letter.
543 static const struct LocationNameInfo {
544 const char* string;
545 char length;
546 bool allow_plural;
547 } location_names[159] = {{"alley", 5, false}, {"annex", 5, false},
548 {"arcade", 6, false}, {"ave", 3, false},
549 {"ave.", 4, false}, {"avenue", 6, false},
550 {"alameda", 7, false}, {"bayou", 5, false},
551 {"beach", 5, false}, {"bend", 4, false},
552 {"bluff", 5, true}, {"bottom", 6, false},
553 {"boulevard", 9, false}, {"branch", 6, false},
554 {"bridge", 6, false}, {"brook", 5, true},
555 {"burg", 4, true}, {"bypass", 6, false},
556 {"broadway", 8, false}, {"camino", 6, false},
557 {"camp", 4, false}, {"canyon", 6, false},
558 {"cape", 4, false}, {"causeway", 8, false},
559 {"center", 6, true}, {"circle", 6, true},
560 {"cliff", 5, true}, {"club", 4, false},
561 {"common", 6, false}, {"corner", 6, true},
562 {"course", 6, false}, {"court", 5, true},
563 {"cove", 4, true}, {"creek", 5, false},
564 {"crescent", 8, false}, {"crest", 5, false},
565 {"crossing", 8, false}, {"crossroad", 9, false},
566 {"curve", 5, false}, {"circulo", 7, false},
567 {"dale", 4, false}, {"dam", 3, false},
568 {"divide", 6, false}, {"drive", 5, true},
569 {"estate", 6, true}, {"expressway", 10, false},
570 {"extension", 9, true}, {"fall", 4, true},
571 {"ferry", 5, false}, {"field", 5, true},
572 {"flat", 4, true}, {"ford", 4, true},
573 {"forest", 6, false}, {"forge", 5, true},
574 {"fork", 4, true}, {"fort", 4, false},
575 {"freeway", 7, false}, {"garden", 6, true},
576 {"gateway", 7, false}, {"glen", 4, true},
577 {"green", 5, true}, {"grove", 5, true},
578 {"harbor", 6, true}, {"haven", 5, false},
579 {"heights", 7, false}, {"highway", 7, false},
580 {"hill", 4, true}, {"hollow", 6, false},
581 {"inlet", 5, false}, {"island", 6, true},
582 {"isle", 4, false}, {"junction", 8, true},
583 {"key", 3, true}, {"knoll", 5, true},
584 {"lake", 4, true}, {"land", 4, false},
585 {"landing", 7, false}, {"lane", 4, false},
586 {"light", 5, true}, {"loaf", 4, false},
587 {"lock", 4, true}, {"lodge", 5, false},
588 {"loop", 4, false}, {"mall", 4, false},
589 {"manor", 5, true}, {"meadow", 6, true},
590 {"mews", 4, false}, {"mill", 4, true},
591 {"mission", 7, false}, {"motorway", 8, false},
592 {"mount", 5, false}, {"mountain", 8, true},
593 {"neck", 4, false}, {"orchard", 7, false},
594 {"oval", 4, false}, {"overpass", 8, false},
595 {"park", 4, true}, {"parkway", 7, true},
596 {"pass", 4, false}, {"passage", 7, false},
597 {"path", 4, false}, {"pike", 4, false},
598 {"pine", 4, true}, {"plain", 5, true},
599 {"plaza", 5, false}, {"point", 5, true},
600 {"port", 4, true}, {"prairie", 7, false},
601 {"privada", 7, false}, {"radial", 6, false},
602 {"ramp", 4, false}, {"ranch", 5, false},
603 {"rapid", 5, true}, {"rd", 2, false},
604 {"rd.", 3, false}, {"rest", 4, false},
605 {"ridge", 5, true}, {"river", 5, false},
606 {"road", 4, true}, {"route", 5, false},
607 {"row", 3, false}, {"rue", 3, false},
608 {"run", 3, false}, {"shoal", 5, true},
609 {"shore", 5, true}, {"skyway", 6, false},
610 {"spring", 6, true}, {"spur", 4, true},
611 {"square", 6, true}, {"station", 7, false},
612 {"stravenue", 9, false}, {"stream", 6, false},
613 {"st", 2, false}, {"st.", 3, false},
614 {"street", 6, true}, {"summit", 6, false},
615 {"speedway", 8, false}, {"terrace", 7, false},
616 {"throughway", 10, false}, {"trace", 5, false},
617 {"track", 5, false}, {"trafficway", 10, false},
618 {"trail", 5, false}, {"tunnel", 6, false},
619 {"turnpike", 8, false}, {"underpass", 9, false},
620 {"union", 5, true}, {"valley", 6, true},
621 {"viaduct", 7, false}, {"view", 4, true},
622 {"village", 7, true}, {"ville", 5, false},
623 {"vista", 5, false}, {"walk", 4, true},
624 {"wall", 4, false}, {"way", 3, true},
625 {"well", 4, true}, {"xing", 4, false},
626 {"xrd", 3, false}};
627
628 // Accumulative number of location names for each starting letter.
629 static const int location_names_accumulative[25] = {
630 0, 7, 19, 40, 44, 47, 57, 62, 68, 71, 72, 74, 83,
631 92, 93, 96, 109, 109, 123, 137, 145, 147, 153, 157, 159};
632
633 DCHECK_EQ(
634 location_names_accumulative[arraysize(location_names_accumulative) - 1],
635 static_cast<int>(arraysize(location_names)));
636
637 if (!base::IsAsciiAlpha(*word.begin))
638 return false;
639
640 // No location names start with y, z.
641 base::char16 first_letter = base::ToLowerASCII(*word.begin);
642 if (first_letter > 'x')
643 return false;
644
645 DCHECK(first_letter >= 'a');
646 int index = first_letter - 'a';
647 int length = std::distance(word.begin, word.end);
648 for (int i = location_names_accumulative[index];
649 i < location_names_accumulative[index + 1]; ++i) {
650 if (location_names[i].length != length &&
651 (location_names[i].allow_plural &&
652 location_names[i].length + 1 != length)) {
653 continue;
654 }
655
656 if (LowerCaseEqualsASCIIWithPlural(word.begin, word.end,
657 location_names[i].string,
658 location_names[i].allow_plural)) {
659 return true;
660 }
661 }
662
663 return false;
664 }
665
666 } // namespace internal
667
668 } // namespace address_parser
669
670 } // namespace android_webview
OLDNEW
« no previous file with comments | « android_webview/native/address_parser_internal.h ('k') | android_webview/native/address_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698