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 31namespace i18n { 32namespace phonenumbers { 33 34using std::make_pair; 35using std::map; 36using std::string; 37 38bool 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 47ShortNumberInfo::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. 66const 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 76bool ShortNumberInfo::ConnectsToEmergencyNumber(const string& number, 77 const string& region_code) const { 78 return MatchesEmergencyNumberHelper(number, region_code, 79 true /* allows prefix match */); 80} 81 82bool 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 88bool 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