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 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 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. 66 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 76 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 82 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 88 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