Fully quality std::* names.
[platform/upstream/libphonenumber.git] / cpp / src / phonenumbers / phonenumberutil.cc
index d966a35..9904145 100644 (file)
 #include <string.h>
 #include <algorithm>
 #include <cctype>
-#include <fstream>
-#include <iostream>
 #include <iterator>
 #include <map>
-#include <sstream>
 #include <utility>
 #include <vector>
 
 namespace i18n {
 namespace phonenumbers {
 
-using std::cerr;
-using std::endl;
-using std::ifstream;
-using std::make_pair;
-using std::sort;
-using std::stringstream;
-
 using google::protobuf::RepeatedPtrField;
 
+// static constants
+const size_t PhoneNumberUtil::kMinLengthForNsn;
+const size_t PhoneNumberUtil::kMaxLengthForNsn;
+const size_t PhoneNumberUtil::kMaxLengthCountryCode;
+const int PhoneNumberUtil::kNanpaCountryCode;
+
 // static
 const char PhoneNumberUtil::kPlusChars[] = "+\xEF\xBC\x8B";  /* "++" */
 // To find out the unicode code-point of the characters below in vim, highlight
@@ -118,7 +114,7 @@ const char kSingleExtnSymbolsForMatching[] =
 
 bool LoadCompiledInMetadata(PhoneMetadataCollection* metadata) {
   if (!metadata->ParseFromArray(metadata_get(), metadata_size())) {
-    cerr << "Could not parse binary data." << endl;
+    LOG(ERROR) << "Could not parse binary data.";
     return false;
   }
   return true;
@@ -194,92 +190,6 @@ bool IsNationalNumberSuffixOfTheOther(const PhoneNumber& first_number,
                          first_number_national_number);
 }
 
-bool IsNumberMatchingDesc(const string& national_number,
-                          const PhoneNumberDesc& number_desc,
-                          RegExpCache* regexp_cache) {
-  return regexp_cache->GetRegExp(number_desc.possible_number_pattern())
-             .FullMatch(national_number) &&
-         regexp_cache->GetRegExp(number_desc.national_number_pattern())
-             .FullMatch(national_number);
-}
-
-PhoneNumberUtil::PhoneNumberType GetNumberTypeHelper(
-    const string& national_number, const PhoneMetadata& metadata,
-    RegExpCache* regexp_cache) {
-  const PhoneNumberDesc& general_desc = metadata.general_desc();
-  if (!general_desc.has_national_number_pattern() ||
-      !IsNumberMatchingDesc(national_number, general_desc, regexp_cache)) {
-    VLOG(4) << "Number type unknown - doesn't match general national number"
-            << " pattern.";
-    return PhoneNumberUtil::UNKNOWN;
-  }
-  if (IsNumberMatchingDesc(national_number, metadata.premium_rate(),
-                           regexp_cache)) {
-    VLOG(4) << "Number is a premium number.";
-    return PhoneNumberUtil::PREMIUM_RATE;
-  }
-  if (IsNumberMatchingDesc(national_number, metadata.toll_free(),
-                           regexp_cache)) {
-    VLOG(4) << "Number is a toll-free number.";
-    return PhoneNumberUtil::TOLL_FREE;
-  }
-  if (IsNumberMatchingDesc(national_number, metadata.shared_cost(),
-                           regexp_cache)) {
-    VLOG(4) << "Number is a shared cost number.";
-    return PhoneNumberUtil::SHARED_COST;
-  }
-  if (IsNumberMatchingDesc(national_number, metadata.voip(), regexp_cache)) {
-    VLOG(4) << "Number is a VOIP (Voice over IP) number.";
-    return PhoneNumberUtil::VOIP;
-  }
-  if (IsNumberMatchingDesc(national_number, metadata.personal_number(),
-                           regexp_cache)) {
-    VLOG(4) << "Number is a personal number.";
-    return PhoneNumberUtil::PERSONAL_NUMBER;
-  }
-  if (IsNumberMatchingDesc(national_number, metadata.pager(), regexp_cache)) {
-    VLOG(4) << "Number is a pager number.";
-    return PhoneNumberUtil::PAGER;
-  }
-  if (IsNumberMatchingDesc(national_number, metadata.uan(), regexp_cache)) {
-    VLOG(4) << "Number is a UAN.";
-    return PhoneNumberUtil::UAN;
-  }
-  if (IsNumberMatchingDesc(national_number, metadata.voicemail(),
-                           regexp_cache)) {
-    VLOG(4) << "Number is a voicemail number.";
-    return PhoneNumberUtil::VOICEMAIL;
-  }
-
-  bool is_fixed_line =
-      IsNumberMatchingDesc(national_number, metadata.fixed_line(),
-                           regexp_cache);
-  if (is_fixed_line) {
-    if (metadata.same_mobile_and_fixed_line_pattern()) {
-      VLOG(4) << "Fixed-line and mobile patterns equal, number is fixed-line"
-              << " or mobile";
-      return PhoneNumberUtil::FIXED_LINE_OR_MOBILE;
-    } else if (IsNumberMatchingDesc(national_number, metadata.mobile(),
-                                    regexp_cache)) {
-      VLOG(4) << "Fixed-line and mobile patterns differ, but number is "
-              << "still fixed-line or mobile";
-      return PhoneNumberUtil::FIXED_LINE_OR_MOBILE;
-    }
-    VLOG(4) << "Number is a fixed line number.";
-    return PhoneNumberUtil::FIXED_LINE;
-  }
-  // Otherwise, test to see if the number is mobile. Only do this if certain
-  // that the patterns for mobile and fixed line aren't the same.
-  if (!metadata.same_mobile_and_fixed_line_pattern() &&
-      IsNumberMatchingDesc(national_number, metadata.mobile(), regexp_cache)) {
-    VLOG(4) << "Number is a mobile number.";
-    return PhoneNumberUtil::MOBILE;
-  }
-  VLOG(4) << "Number type unknown - doesn\'t match any specific number type"
-          << " pattern.";
-  return PhoneNumberUtil::UNKNOWN;
-}
-
 char32 ToUnicodeCodepoint(const char* unicode_char) {
   char32 codepoint;
   EncodingUtils::DecodeUTF8Char(unicode_char, &codepoint);
@@ -376,70 +286,70 @@ void PhoneNumberUtil::SetLogger(Logger* logger) {
 class PhoneNumberRegExpsAndMappings {
  private:
   void InitializeMapsAndSets() {
-    diallable_char_mappings_.insert(make_pair('+', '+'));
-    diallable_char_mappings_.insert(make_pair('*', '*'));
+    diallable_char_mappings_.insert(std::make_pair('+', '+'));
+    diallable_char_mappings_.insert(std::make_pair('*', '*'));
     // Here we insert all punctuation symbols that we wish to respect when
     // formatting alpha numbers, as they show the intended number groupings.
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("-"), '-'));
+        std::make_pair(ToUnicodeCodepoint("-"), '-'));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("\xEF\xBC\x8D" /* "-" */), '-'));
+        std::make_pair(ToUnicodeCodepoint("\xEF\xBC\x8D" /* "-" */), '-'));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("\xE2\x80\x90" /* "‐" */), '-'));
+        std::make_pair(ToUnicodeCodepoint("\xE2\x80\x90" /* "‐" */), '-'));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("\xE2\x80\x91" /* "‑" */), '-'));
+        std::make_pair(ToUnicodeCodepoint("\xE2\x80\x91" /* "‑" */), '-'));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("\xE2\x80\x92" /* "‒" */), '-'));
+        std::make_pair(ToUnicodeCodepoint("\xE2\x80\x92" /* "‒" */), '-'));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("\xE2\x80\x93" /* "–" */), '-'));
+        std::make_pair(ToUnicodeCodepoint("\xE2\x80\x93" /* "–" */), '-'));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("\xE2\x80\x94" /* "—" */), '-'));
+        std::make_pair(ToUnicodeCodepoint("\xE2\x80\x94" /* "—" */), '-'));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("\xE2\x80\x95" /* "―" */), '-'));
+        std::make_pair(ToUnicodeCodepoint("\xE2\x80\x95" /* "―" */), '-'));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("\xE2\x88\x92" /* "−" */), '-'));
+        std::make_pair(ToUnicodeCodepoint("\xE2\x88\x92" /* "−" */), '-'));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("/"), '/'));
+        std::make_pair(ToUnicodeCodepoint("/"), '/'));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("\xEF\xBC\x8F" /* "/" */), '/'));
+        std::make_pair(ToUnicodeCodepoint("\xEF\xBC\x8F" /* "/" */), '/'));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint(" "), ' '));
+        std::make_pair(ToUnicodeCodepoint(" "), ' '));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("\xE3\x80\x80" /* " " */), ' '));
+        std::make_pair(ToUnicodeCodepoint("\xE3\x80\x80" /* " " */), ' '));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("\xE2\x81\xA0"), ' '));
+        std::make_pair(ToUnicodeCodepoint("\xE2\x81\xA0"), ' '));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("."), '.'));
+        std::make_pair(ToUnicodeCodepoint("."), '.'));
     all_plus_number_grouping_symbols_.insert(
-        make_pair(ToUnicodeCodepoint("\xEF\xBC\x8E" /* "." */), '.'));
+        std::make_pair(ToUnicodeCodepoint("\xEF\xBC\x8E" /* "." */), '.'));
     // Only the upper-case letters are added here - the lower-case versions are
     // added programmatically.
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("A"), '2'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("B"), '2'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("C"), '2'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("D"), '3'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("E"), '3'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("F"), '3'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("G"), '4'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("H"), '4'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("I"), '4'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("J"), '5'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("K"), '5'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("L"), '5'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("M"), '6'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("N"), '6'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("O"), '6'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("P"), '7'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("Q"), '7'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("R"), '7'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("S"), '7'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("T"), '8'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("U"), '8'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("V"), '8'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("W"), '9'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("X"), '9'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("Y"), '9'));
-    alpha_mappings_.insert(make_pair(ToUnicodeCodepoint("Z"), '9'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("A"), '2'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("B"), '2'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("C"), '2'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("D"), '3'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("E"), '3'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("F"), '3'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("G"), '4'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("H"), '4'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("I"), '4'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("J"), '5'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("K"), '5'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("L"), '5'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("M"), '6'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("N"), '6'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("O"), '6'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("P"), '7'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("Q"), '7'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("R"), '7'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("S"), '7'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("T"), '8'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("U"), '8'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("V"), '8'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("W"), '9'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("X"), '9'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("Y"), '9'));
+    alpha_mappings_.insert(std::make_pair(ToUnicodeCodepoint("Z"), '9'));
     map<char32, char> lower_case_mappings;
     map<char32, char> alpha_letters;
     for (map<char32, char>::const_iterator it = alpha_mappings_.begin();
@@ -449,12 +359,12 @@ class PhoneNumberRegExpsAndMappings {
       if (it->first < 128) {
         char letter_as_upper = static_cast<char>(it->first);
         char32 letter_as_lower = static_cast<char32>(tolower(letter_as_upper));
-        lower_case_mappings.insert(make_pair(letter_as_lower, it->second));
+        lower_case_mappings.insert(std::make_pair(letter_as_lower, it->second));
         // Add the letters in both variants to the alpha_letters map. This just
         // pairs each letter with its upper-case representation so that it can
         // be retained when normalising alpha numbers.
-        alpha_letters.insert(make_pair(letter_as_lower, letter_as_upper));
-        alpha_letters.insert(make_pair(it->first, letter_as_upper));
+        alpha_letters.insert(std::make_pair(letter_as_lower, letter_as_upper));
+        alpha_letters.insert(std::make_pair(it->first, letter_as_upper));
       }
     }
     // In the Java version we don't insert the lower-case mappings in the map,
@@ -469,13 +379,13 @@ class PhoneNumberRegExpsAndMappings {
                                              alpha_letters.end());
     // Add the ASCII digits so that they don't get deleted by NormalizeHelper().
     for (char c = '0'; c <= '9'; ++c) {
-      diallable_char_mappings_.insert(make_pair(c, c));
-      alpha_phone_mappings_.insert(make_pair(c, c));
-      all_plus_number_grouping_symbols_.insert(make_pair(c, c));
+      diallable_char_mappings_.insert(std::make_pair(c, c));
+      alpha_phone_mappings_.insert(std::make_pair(c, c));
+      all_plus_number_grouping_symbols_.insert(std::make_pair(c, c));
     }
 
-    mobile_token_mappings_.insert(make_pair(52, '1'));
-    mobile_token_mappings_.insert(make_pair(54, '9'));
+    mobile_token_mappings_.insert(std::make_pair(52, '1'));
+    mobile_token_mappings_.insert(std::make_pair(54, '9'));
   }
 
   // Small string helpers since StrCat has a maximum number of arguments. These
@@ -698,9 +608,9 @@ PhoneNumberUtil::PhoneNumberUtil()
     int country_calling_code = it->country_code();
     if (kRegionCodeForNonGeoEntity == region_code) {
       country_code_to_non_geographical_metadata_map_->insert(
-          make_pair(country_calling_code, *it));
+          std::make_pair(country_calling_code, *it));
     } else {
-      region_to_metadata_map_->insert(make_pair(region_code, *it));
+      region_to_metadata_map_->insert(std::make_pair(region_code, *it));
     }
     map<int, list<string>* >::iterator calling_code_in_map =
         country_calling_code_to_region_map.find(country_calling_code);
@@ -715,7 +625,7 @@ PhoneNumberUtil::PhoneNumberUtil()
       list<string>* list_with_region_code = new list<string>();
       list_with_region_code->push_back(region_code);
       country_calling_code_to_region_map.insert(
-          make_pair(country_calling_code, list_with_region_code));
+          std::make_pair(country_calling_code, list_with_region_code));
     }
     if (country_calling_code == kNanpaCountryCode) {
         nanpa_regions_->insert(region_code);
@@ -727,9 +637,9 @@ PhoneNumberUtil::PhoneNumberUtil()
       country_calling_code_to_region_map.begin(),
       country_calling_code_to_region_map.end());
   // Sort all the pairs in ascending order according to country calling code.
-  sort(country_calling_code_to_region_code_map_->begin(),
-       country_calling_code_to_region_code_map_->end(),
-       OrderByFirst());
+  std::sort(country_calling_code_to_region_code_map_->begin(),
+            country_calling_code_to_region_code_map_->end(),
+            OrderByFirst());
 }
 
 PhoneNumberUtil::~PhoneNumberUtil() {
@@ -747,6 +657,16 @@ void PhoneNumberUtil::GetSupportedRegions(set<string>* regions) const {
   }
 }
 
+void PhoneNumberUtil::GetSupportedGlobalNetworkCallingCodes(
+    set<int>* calling_codes) const {
+  DCHECK(calling_codes);
+  for (map<int, PhoneMetadata>::const_iterator it =
+           country_code_to_non_geographical_metadata_map_->begin();
+       it != country_code_to_non_geographical_metadata_map_->end(); ++it) {
+    calling_codes->insert(it->first);
+  }
+}
+
 // Public wrapper function to get a PhoneNumberUtil instance with the default
 // metadata file.
 // static
@@ -1047,8 +967,9 @@ void PhoneNumberUtil::FormatNumberForMobileDialing(
   number_no_extension.clear_extension();
   string region_code;
   GetRegionCodeForCountryCode(country_calling_code, &region_code);
+  PhoneNumberType number_type = GetNumberType(number_no_extension);
+  bool is_valid_number = (number_type != UNKNOWN);
   if (calling_from == region_code) {
-    PhoneNumberType number_type = GetNumberType(number_no_extension);
     bool is_fixed_line_or_mobile =
         (number_type == FIXED_LINE) || (number_type == MOBILE) ||
         (number_type == FIXED_LINE_OR_MOBILE);
@@ -1068,23 +989,38 @@ void PhoneNumberUtil::FormatNumberForMobileDialing(
         // string here.
         formatted_number->assign("");
       }
-    } else if (region_code == "HU") {
+    } else if (is_valid_number && region_code == "HU") {
       // The national format for HU numbers doesn't contain the national prefix,
       // because that is how numbers are normally written down. However, the
-      // national prefix is obligatory when dialing from a mobile phone. As a
-      // result, we add it back here.
+      // national prefix is obligatory when dialing from a mobile phone, except
+      // for short numbers. As a result, we add it back here if it is a valid
+      // regular length phone number.
       Format(number_no_extension, NATIONAL, formatted_number);
       string hu_national_prefix;
       GetNddPrefixForRegion(region_code, true /* strip non-digits */,
                             &hu_national_prefix);
       formatted_number->assign(
           StrCat(hu_national_prefix, " ", *formatted_number));
+    } else if (country_calling_code == kNanpaCountryCode) {
+      // For NANPA countries, we output international format for numbers that
+      // can be dialed internationally, since that always works, except for
+      // numbers which might potentially be short numbers, which are always
+      // dialled in national format.
+      const PhoneMetadata* region_metadata = GetMetadataForRegion(calling_from);
+      string national_number;
+      GetNationalSignificantNumber(number_no_extension, &national_number);
+      if (CanBeInternationallyDialled(number_no_extension) &&
+          !IsShorterThanPossibleNormalNumber(region_metadata,
+              national_number)) {
+        Format(number_no_extension, INTERNATIONAL, formatted_number);
+      } else {
+        Format(number_no_extension, NATIONAL, formatted_number);
+      }
     } else {
-      // For NANPA countries, non-geographical countries, Mexican and Chilean
-      // fixed line and mobile numbers, we output international format for
-      // numbers that can be dialed internationally as that always works.
-      if ((country_calling_code == kNanpaCountryCode ||
-           region_code == kRegionCodeForNonGeoEntity ||
+      // For non-geographical countries, and Mexican and Chilean fixed line and
+      // mobile numbers, we output international format for numbers that can be
+      // dialed internationally as that always works.
+      if ((region_code == kRegionCodeForNonGeoEntity ||
            // MX fixed line and mobile numbers should always be formatted in
            // international format, even when dialed within MX. For national
            // format to work, a carrier code needs to be used, and the correct
@@ -1104,7 +1040,11 @@ void PhoneNumberUtil::FormatNumberForMobileDialing(
         Format(number_no_extension, NATIONAL, formatted_number);
       }
     }
-  } else if (CanBeInternationallyDialled(number_no_extension)) {
+  } else if (is_valid_number &&
+      CanBeInternationallyDialled(number_no_extension)) {
+    // We assume that short numbers are not diallable from outside their
+    // region, so if a number is not a valid regular length phone number, we
+    // treat it as if it cannot be internationally dialled.
     with_formatting
         ? Format(number_no_extension, INTERNATIONAL, formatted_number)
         : Format(number_no_extension, E164, formatted_number);
@@ -1673,8 +1613,7 @@ void PhoneNumberUtil::GetRegionCodeForNumberFromRegionList(
         *region_code = *it;
         return;
       }
-    } else if (GetNumberTypeHelper(national_number, *metadata,
-                                   reg_exps_->regexp_cache_.get()) != UNKNOWN) {
+    } else if (GetNumberTypeHelper(national_number, *metadata) != UNKNOWN) {
       *region_code = *it;
       return;
     }
@@ -1818,13 +1757,17 @@ void PhoneNumberUtil::BuildNationalNumberForParsing(
 
     // Now append everything between the "tel:" prefix and the phone-context.
     // This should include the national number, an optional extension or
-    // isdn-subaddress component.
-    int end_of_rfc_prefix =
-        number_to_parse.find(kRfc3966Prefix) + strlen(kRfc3966Prefix);
+    // isdn-subaddress component. Note we also handle the case when "tel:" is
+    // missing, as we have seen in some of the phone number inputs. In that
+    // case, we append everything from the beginning.
+    size_t index_of_rfc_prefix = number_to_parse.find(kRfc3966Prefix);
+    int index_of_national_number = (index_of_rfc_prefix != string::npos) ?
+        index_of_rfc_prefix + strlen(kRfc3966Prefix) : 0;
     StrAppend(
         national_number,
-        number_to_parse.substr(end_of_rfc_prefix,
-                               index_of_phone_context - end_of_rfc_prefix));
+        number_to_parse.substr(
+            index_of_national_number,
+            index_of_phone_context - index_of_national_number));
   } else {
     // Extract a possible number from the string passed in (this strips leading
     // characters that could not be the start of a phone number.)
@@ -1921,11 +1864,22 @@ PhoneNumberUtil::ErrorType PhoneNumberUtil::ParseHelper(
     return TOO_SHORT_NSN;
   }
   if (country_metadata) {
-    string* carrier_code = keep_raw_input ?
-        temp_number.mutable_preferred_domestic_carrier_code() : NULL;
+    string carrier_code;
+    string potential_national_number(normalized_national_number);
     MaybeStripNationalPrefixAndCarrierCode(*country_metadata,
-                                           &normalized_national_number,
-                                           carrier_code);
+                                           &potential_national_number,
+                                           &carrier_code);
+    // We require that the NSN remaining after stripping the national prefix
+    // and carrier code be of a possible length for the region. Otherwise, we
+    // don't do the stripping, since the original number could be a valid short
+    // number.
+    if (!IsShorterThanPossibleNormalNumber(country_metadata,
+        potential_national_number)) {
+      normalized_national_number.assign(potential_national_number);
+      if (keep_raw_input) {
+        temp_number.set_preferred_domestic_carrier_code(carrier_code);
+      }
+    }
   }
   size_t normalized_national_number_length =
       normalized_national_number.length();
@@ -1938,13 +1892,12 @@ PhoneNumberUtil::ErrorType PhoneNumberUtil::ParseHelper(
     return TOO_LONG_NSN;
   }
   temp_number.set_country_code(country_code);
-  if (normalized_national_number[0] == '0') {
-    temp_number.set_italian_leading_zero(true);
-  }
+  SetItalianLeadingZerosForPhoneNumber(normalized_national_number,
+      &temp_number);
   uint64 number_as_int;
   safe_strtou64(normalized_national_number, &number_as_int);
   temp_number.set_national_number(number_as_int);
-  phone_number->MergeFrom(temp_number);
+  phone_number->Swap(&temp_number);
   return NO_PARSING_ERROR;
 }
 
@@ -2030,20 +1983,8 @@ PhoneNumberUtil::ValidationResult PhoneNumberUtil::IsPossibleNumberWithReason(
   // Metadata cannot be NULL because the country calling code is valid.
   const PhoneMetadata* metadata =
       GetMetadataForRegionOrCallingCode(country_code, region_code);
-  const PhoneNumberDesc& general_num_desc = metadata->general_desc();
-  // Handling case of numbers with no metadata.
-  if (!general_num_desc.has_national_number_pattern()) {
-    size_t number_length = national_number.length();
-    if (number_length < kMinLengthForNsn) {
-      return TOO_SHORT;
-    } else if (number_length > kMaxLengthForNsn) {
-      return TOO_LONG;
-    } else {
-      return IS_POSSIBLE;
-    }
-  }
   const RegExp& possible_number_pattern = reg_exps_->regexp_cache_->GetRegExp(
-      StrCat("(", general_num_desc.possible_number_pattern(), ")"));
+      StrCat("(", metadata->general_desc().possible_number_pattern(), ")"));
   return TestNumberLengthAgainstPattern(possible_number_pattern,
                                         national_number);
 }
@@ -2077,9 +2018,7 @@ PhoneNumberUtil::PhoneNumberType PhoneNumberUtil::GetNumberType(
   }
   string national_significant_number;
   GetNationalSignificantNumber(number, &national_significant_number);
-  return GetNumberTypeHelper(national_significant_number,
-                             *metadata,
-                             reg_exps_->regexp_cache_.get());
+  return GetNumberTypeHelper(national_significant_number, *metadata);
 }
 
 bool PhoneNumberUtil::IsValidNumber(const PhoneNumber& number) const {
@@ -2100,22 +2039,10 @@ bool PhoneNumberUtil::IsValidNumberForRegion(const PhoneNumber& number,
     // number does not match that of the region code.
     return false;
   }
-  const PhoneNumberDesc& general_desc = metadata->general_desc();
   string national_number;
   GetNationalSignificantNumber(number, &national_number);
 
-  // For regions where we don't have metadata for PhoneNumberDesc, we treat
-  // any number passed in as a valid number if its national significant number
-  // is between the minimum and maximum lengths defined by ITU for a national
-  // significant number.
-  if (!general_desc.has_national_number_pattern()) {
-    VLOG(3) << "Validating number with incomplete metadata.";
-    size_t number_length = national_number.length();
-    return number_length > kMinLengthForNsn &&
-        number_length <= kMaxLengthForNsn;
-  }
-  return GetNumberTypeHelper(national_number, *metadata,
-                             reg_exps_->regexp_cache_.get()) != UNKNOWN;
+  return GetNumberTypeHelper(national_number, *metadata) != UNKNOWN;
 }
 
 bool PhoneNumberUtil::IsNumberGeographical(
@@ -2136,13 +2063,115 @@ bool PhoneNumberUtil::IsLeadingZeroPossible(int country_calling_code) const {
   return main_metadata_for_calling_code->leading_zero_possible();
 }
 
+// A helper function to set the values related to leading zeros in a
+// PhoneNumber.
+void PhoneNumberUtil::SetItalianLeadingZerosForPhoneNumber(
+    const string& national_number, PhoneNumber* phone_number) const {
+  if (national_number.length() > 1 && national_number[0] == '0') {
+    phone_number->set_italian_leading_zero(true);
+    size_t number_of_leading_zeros = 1;
+    // Note that if the national number is all "0"s, the last "0" is not
+    // counted as a leading zero.
+    while (number_of_leading_zeros < national_number.length() - 1 &&
+        national_number[number_of_leading_zeros] == '0') {
+      number_of_leading_zeros++;
+    }
+    if (number_of_leading_zeros != 1) {
+      phone_number->set_number_of_leading_zeros(number_of_leading_zeros);
+    }
+  }
+}
+
+bool PhoneNumberUtil::IsNumberPossibleForDesc(
+    const string& national_number, const PhoneNumberDesc& number_desc) const {
+  return reg_exps_->regexp_cache_.get()->
+             GetRegExp(number_desc.possible_number_pattern())
+             .FullMatch(national_number);
+}
+
+bool PhoneNumberUtil::IsNumberMatchingDesc(
+    const string& national_number, const PhoneNumberDesc& number_desc) const {
+  return IsNumberPossibleForDesc(national_number, number_desc) &&
+         reg_exps_->regexp_cache_.get()->
+             GetRegExp(number_desc.national_number_pattern())
+             .FullMatch(national_number);
+}
+
+PhoneNumberUtil::PhoneNumberType PhoneNumberUtil::GetNumberTypeHelper(
+    const string& national_number, const PhoneMetadata& metadata) const {
+  if (!IsNumberMatchingDesc(national_number, metadata.general_desc())) {
+    VLOG(4) << "Number type unknown - doesn't match general national number"
+            << " pattern.";
+    return PhoneNumberUtil::UNKNOWN;
+  }
+  if (IsNumberMatchingDesc(national_number, metadata.premium_rate())) {
+    VLOG(4) << "Number is a premium number.";
+    return PhoneNumberUtil::PREMIUM_RATE;
+  }
+  if (IsNumberMatchingDesc(national_number, metadata.toll_free())) {
+    VLOG(4) << "Number is a toll-free number.";
+    return PhoneNumberUtil::TOLL_FREE;
+  }
+  if (IsNumberMatchingDesc(national_number, metadata.shared_cost())) {
+    VLOG(4) << "Number is a shared cost number.";
+    return PhoneNumberUtil::SHARED_COST;
+  }
+  if (IsNumberMatchingDesc(national_number, metadata.voip())) {
+    VLOG(4) << "Number is a VOIP (Voice over IP) number.";
+    return PhoneNumberUtil::VOIP;
+  }
+  if (IsNumberMatchingDesc(national_number, metadata.personal_number())) {
+    VLOG(4) << "Number is a personal number.";
+    return PhoneNumberUtil::PERSONAL_NUMBER;
+  }
+  if (IsNumberMatchingDesc(national_number, metadata.pager())) {
+    VLOG(4) << "Number is a pager number.";
+    return PhoneNumberUtil::PAGER;
+  }
+  if (IsNumberMatchingDesc(national_number, metadata.uan())) {
+    VLOG(4) << "Number is a UAN.";
+    return PhoneNumberUtil::UAN;
+  }
+  if (IsNumberMatchingDesc(national_number, metadata.voicemail())) {
+    VLOG(4) << "Number is a voicemail number.";
+    return PhoneNumberUtil::VOICEMAIL;
+  }
+
+  bool is_fixed_line =
+      IsNumberMatchingDesc(national_number, metadata.fixed_line());
+  if (is_fixed_line) {
+    if (metadata.same_mobile_and_fixed_line_pattern()) {
+      VLOG(4) << "Fixed-line and mobile patterns equal, number is fixed-line"
+              << " or mobile";
+      return PhoneNumberUtil::FIXED_LINE_OR_MOBILE;
+    } else if (IsNumberMatchingDesc(national_number, metadata.mobile())) {
+      VLOG(4) << "Fixed-line and mobile patterns differ, but number is "
+              << "still fixed-line or mobile";
+      return PhoneNumberUtil::FIXED_LINE_OR_MOBILE;
+    }
+    VLOG(4) << "Number is a fixed line number.";
+    return PhoneNumberUtil::FIXED_LINE;
+  }
+  // Otherwise, test to see if the number is mobile. Only do this if certain
+  // that the patterns for mobile and fixed line aren't the same.
+  if (!metadata.same_mobile_and_fixed_line_pattern() &&
+      IsNumberMatchingDesc(national_number, metadata.mobile())) {
+    VLOG(4) << "Number is a mobile number.";
+    return PhoneNumberUtil::MOBILE;
+  }
+  VLOG(4) << "Number type unknown - doesn\'t match any specific number type"
+          << " pattern.";
+  return PhoneNumberUtil::UNKNOWN;
+}
+
 void PhoneNumberUtil::GetNationalSignificantNumber(
     const PhoneNumber& number,
     string* national_number) const {
   DCHECK(national_number);
-  // If a leading zero has been set, we prefix this now. Note this is not a
+  // If leading zero(s) have been set, we prefix this now. Note this is not a
   // national prefix.
-  StrAppend(national_number, number.italian_leading_zero() ? "0" : "");
+  StrAppend(national_number, number.italian_leading_zero() ?
+      string(number.number_of_leading_zeros(), '0') : "");
   StrAppend(national_number, number.national_number());
 }
 
@@ -2738,6 +2767,15 @@ AsYouTypeFormatter* PhoneNumberUtil::GetAsYouTypeFormatter(
   return new AsYouTypeFormatter(region_code);
 }
 
+bool PhoneNumberUtil::IsShorterThanPossibleNormalNumber(
+    const PhoneMetadata* country_metadata, const string& number) const {
+  const RegExp& possible_number_pattern =
+      reg_exps_->regexp_cache_->GetRegExp(StrCat("(",
+          country_metadata->general_desc().possible_number_pattern(), ")"));
+  return TestNumberLengthAgainstPattern(possible_number_pattern, number) ==
+      PhoneNumberUtil::TOO_SHORT;
+}
+
 bool PhoneNumberUtil::CanBeInternationallyDialled(
     const PhoneNumber& number) const {
   string region_code;
@@ -2751,8 +2789,7 @@ bool PhoneNumberUtil::CanBeInternationallyDialled(
   string national_significant_number;
   GetNationalSignificantNumber(number, &national_significant_number);
   return !IsNumberMatchingDesc(
-      national_significant_number, metadata->no_international_dialling(),
-      reg_exps_->regexp_cache_.get());
+      national_significant_number, metadata->no_international_dialling());
 }
 
 }  // namespace phonenumbers