• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2012 The Libphonenumber Authors
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 // Author: David Yonge-Mallo
16 
17 #include "phonenumbers/shortnumberinfo.h"
18 
19 #include <string.h>
20 #include <iterator>
21 #include <map>
22 
23 #include "phonenumbers/base/memory/scoped_ptr.h"
24 #include "phonenumbers/default_logger.h"
25 #include "phonenumbers/phonemetadata.pb.h"
26 #include "phonenumbers/phonenumberutil.h"
27 #include "phonenumbers/regexp_adapter.h"
28 #include "phonenumbers/regexp_factory.h"
29 #include "phonenumbers/short_metadata.h"
30 
31 namespace i18n {
32 namespace phonenumbers {
33 
34 using std::make_pair;
35 using std::map;
36 using std::string;
37 
LoadCompiledInMetadata(PhoneMetadataCollection * metadata)38 bool LoadCompiledInMetadata(PhoneMetadataCollection* metadata) {
39   if (!metadata->ParseFromArray(short_metadata_get(), short_metadata_size())) {
40     LOG(ERROR) << "Could not parse binary data.";
41     return false;
42   }
43   return true;
44 }
45 
46 
ShortNumberInfo()47 ShortNumberInfo::ShortNumberInfo()
48     : phone_util_(*PhoneNumberUtil::GetInstance()),
49       region_to_short_metadata_map_(new map<string, PhoneMetadata>()) {
50   PhoneMetadataCollection metadata_collection;
51   if (!LoadCompiledInMetadata(&metadata_collection)) {
52     LOG(DFATAL) << "Could not parse compiled-in metadata.";
53     return;
54   }
55   for (RepeatedPtrField<PhoneMetadata>::const_iterator it =
56            metadata_collection.metadata().begin();
57        it != metadata_collection.metadata().end();
58        ++it) {
59     const string& region_code = it->id();
60     region_to_short_metadata_map_->insert(make_pair(region_code, *it));
61   }
62 }
63 
64 // Returns a pointer to the phone metadata for the appropriate region or NULL
65 // if the region code is invalid or unknown.
GetMetadataForRegion(const string & region_code) const66 const PhoneMetadata* ShortNumberInfo::GetMetadataForRegion(
67     const string& region_code) const {
68   map<string, PhoneMetadata>::const_iterator it =
69       region_to_short_metadata_map_->find(region_code);
70   if (it != region_to_short_metadata_map_->end()) {
71     return &it->second;
72   }
73   return NULL;
74 }
75 
ConnectsToEmergencyNumber(const string & number,const string & region_code) const76 bool ShortNumberInfo::ConnectsToEmergencyNumber(const string& number,
77     const string& region_code) const {
78   return MatchesEmergencyNumberHelper(number, region_code,
79       true /* allows prefix match */);
80 }
81 
IsEmergencyNumber(const string & number,const string & region_code) const82 bool ShortNumberInfo::IsEmergencyNumber(const string& number,
83     const string& region_code) const {
84   return MatchesEmergencyNumberHelper(number, region_code,
85       false /* doesn't allow prefix match */);
86 }
87 
MatchesEmergencyNumberHelper(const string & number,const string & region_code,bool allow_prefix_match) const88 bool ShortNumberInfo::MatchesEmergencyNumberHelper(const string& number,
89     const string& region_code, bool allow_prefix_match) const {
90   string extracted_number;
91   phone_util_.ExtractPossibleNumber(number, &extracted_number);
92   if (phone_util_.StartsWithPlusCharsPattern(extracted_number)) {
93     // Returns false if the number starts with a plus sign. We don't believe
94     // dialing the country code before emergency numbers (e.g. +1911) works,
95     // but later, if that proves to work, we can add additional logic here to
96     // handle it.
97     return false;
98   }
99   const PhoneMetadata* metadata = GetMetadataForRegion(region_code);
100   if (!metadata || !metadata->has_emergency()) {
101     return false;
102   }
103   const scoped_ptr<const AbstractRegExpFactory> regexp_factory(
104       new RegExpFactory());
105   const scoped_ptr<const RegExp> emergency_number_pattern(
106       regexp_factory->CreateRegExp(
107           metadata->emergency().national_number_pattern()));
108   phone_util_.NormalizeDigitsOnly(&extracted_number);
109   const scoped_ptr<RegExpInput> normalized_number_input(
110       regexp_factory->CreateInput(extracted_number));
111 
112   // In Brazil and Chile, emergency numbers don't work when additional digits
113   // are appended.
114   return (!allow_prefix_match ||
115       region_code == "BR" || region_code == "CL")
116       ? emergency_number_pattern->FullMatch(extracted_number)
117       : emergency_number_pattern->Consume(normalized_number_input.get());
118 }
119 
120 }  // namespace phonenumbers
121 }  // namespace i18n
122