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