Home | History | Annotate | Download | only in phonenumbers
      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