Beispiel #1
0
        /**
        * Sets the possible length fields in the metadata from the sets of data passed in. Checks that
        * the length is covered by the "parent" phone number description element if one is present, and
        * if the lengths are exactly the same as this, they are not filled in for efficiency reasons.
        *
        * @param parentDesc  the "general description" element or null if desc is the generalDesc itself
        * @param desc  the PhoneNumberDesc object that we are going to set lengths for
        */
        private static void SetPossibleLengths(SortedSet<int> lengths,
            SortedSet<int> localOnlyLengths, PhoneNumberDesc parentDesc, PhoneNumberDesc.Builder desc)
        {
            // Only add the lengths to this sub-type if they aren't exactly the same as the possible
            // lengths in the general desc (for metadata size reasons).
            if (parentDesc == null || !ArePossibleLengthsEqual(lengths, parentDesc))
                foreach (var length in lengths)
                    if (parentDesc == null || parentDesc.PossibleLengthList.Contains(length))
                        desc.PossibleLengthList.Add(length);
                    else
                        throw new Exception(
#if NET35
                            $"Out-of-range possible length found ({length}), parent lengths {string.Join(", ", parentDesc.PossibleLengthList.Select(x => x.ToString()).ToArray())}.");
#else
                            $"Out-of-range possible length found ({length}), parent lengths {string.Join(", ", parentDesc.PossibleLengthList)}.");
#endif
            // We check that the local-only length isn't also a normal possible length (only relevant for
            // the general-desc, since within elements such as fixed-line we would throw an exception if we
            // saw this) before adding it to the collection of possible local-only lengths.
            foreach (var length in localOnlyLengths)
                if (!lengths.Contains(length))
                    if (parentDesc == null || parentDesc.PossibleLengthLocalOnlyList.Contains(length)
                        || parentDesc.PossibleLengthList.Contains(length))
                        desc.PossibleLengthLocalOnlyList.Add(length);
                    else
                        throw new Exception(
#if NET35
                            $"Out-of-range local-only possible length found ({length}), parent length {string.Join(", ", parentDesc.PossibleLengthLocalOnlyList.Select(x => x.ToString()).ToArray())}.");
#else
                            $"Out-of-range local-only possible length found ({length}), parent length {string.Join(", ", parentDesc.PossibleLengthLocalOnlyList)}.");
#endif
        }
Beispiel #2
0
        /// <summary>
        /// Gets a valid short number for the specified cost category.
        /// </summary>
        ///
        /// <param name="regionCode">the region for which an example short number is needed</param>
        /// <param name="cost">the cost category of number that is needed</param>
        /// <returns> a valid short number for the specified region and cost category. Returns an empty
        ///     string when the metadata does not contain such information, or the cost is UNKNOWN_COST.</returns>
        internal string GetExampleShortNumberForCost(string regionCode, ShortNumberCost cost)
        {
            var phoneMetadata = MetadataManager.GetShortNumberMetadataForRegion(regionCode);

            if (phoneMetadata == null)
            {
                return("");
            }

            PhoneNumberDesc desc = null;

            switch (cost)
            {
            case ShortNumberCost.TOLL_FREE:
                desc = phoneMetadata.TollFree;
                break;

            case ShortNumberCost.STANDARD_RATE:
                desc = phoneMetadata.StandardRate;
                break;

            case ShortNumberCost.PREMIUM_RATE:
                desc = phoneMetadata.PremiumRate;
                break;
                // UNKNOWN_COST numbers are computed by the process of elimination from the other cost
                // categories.
            }
            return(desc?.ExampleNumber ?? string.Empty);
        }
Beispiel #3
0
 // TODO: Once we have benchmarked ShortNumberInfo, consider if it is worth keeping
 // this performance optimization.
 private bool MatchesPossibleNumberAndNationalNumber(String number,
                                                     PhoneNumberDesc numberDesc)
 {
     if (numberDesc.PossibleLengthCount > 0 &&
         !numberDesc.PossibleLengthList.Contains(number.Length))
     {
         return(false);
     }
     return(matcherApi.matchNationalNumber(number, numberDesc, false));
 }
Beispiel #4
0
        /**
         * Processes a phone number description element from the XML file and returns it as a
         * PhoneNumberDesc. If the description element is a fixed line or mobile number, the parent
         * description will be used to fill in the whole element if necessary, or any components that are
         * missing. For all other types, the parent description will only be used to fill in missing
         * components if the type has a partial definition. For example, if no "tollFree" element exists,
         * we assume there are no toll free numbers for that locale, and return a phone number description
         * with "NA" for both the national and possible number patterns.
         *
         * @param generalDesc  a generic phone number description that will be used to fill in missing
         *                     parts of the description
         * @param countryElement  the XML element representing all the country information
         * @param numberType  the name of the number type, corresponding to the appropriate tag in the XML
         *                    file with information about that type
         * @return  complete description of that phone number type
         */
        public static PhoneNumberDesc.Builder ProcessPhoneNumberDescElement(PhoneNumberDesc parentDesc,
                                                                            XElement countryElement, string numberType)
        {
            if (parentDesc == null)
            {
                parentDesc = new PhoneNumberDesc.Builder().Build();
            }
            var phoneNumberDescList = countryElement.GetElementsByTagName(numberType).ToList();
            var numberDesc          = new PhoneNumberDesc.Builder();

            if (phoneNumberDescList.Count == 0)
            {
                // -1 will never match a possible phone number length, so is safe to use to ensure this never
                // matches. We don't leave it empty, since for compression reasons, we use the empty list to
                // mean that the generalDesc possible lengths apply.
                numberDesc.AddPossibleLength(-1);
                return(numberDesc);
            }
            if (phoneNumberDescList.Count > 0)
            {
                if (phoneNumberDescList.Count > 1)
                {
                    throw new Exception($"Multiple elements with type {numberType} found.");
                }
                var element = phoneNumberDescList[0];

                if (parentDesc != null)
                {
                    // New way of handling possible number lengths. We don't do this for the general
                    // description, since these tags won't be present; instead we will calculate its values
                    // based on the values for all the other number type descriptions (see
                    // setPossibleLengthsGeneralDesc).
                    var lengths          = new SortedSet <int>();
                    var localOnlyLengths = new SortedSet <int>();
                    PopulatePossibleLengthSets(element, lengths, localOnlyLengths);
                    SetPossibleLengths(lengths, new SortedSet <int>(), parentDesc, numberDesc);
                }

                var validPattern = element.GetElementsByTagName(NATIONAL_NUMBER_PATTERN).ToList();
                if (validPattern.Any())
                {
                    numberDesc.SetNationalNumberPattern(ValidateRE(validPattern.First().Value, true));
                }

                var exampleNumber = element.GetElementsByTagName(EXAMPLE_NUMBER).ToList();
                if (exampleNumber.Any())
                {
                    numberDesc.SetExampleNumber(exampleNumber.First().Value);
                }
            }
            return(numberDesc);
        }
Beispiel #5
0
 /**
 * Checks if the possible lengths provided as a sorted set are equal to the possible lengths
 * stored already in the description pattern. Note that possibleLengths may be empty but must not
 * be null, and the PhoneNumberDesc passed in should also not be null.
 */
 private static bool ArePossibleLengthsEqual(SortedSet<int> possibleLengths,
     PhoneNumberDesc desc)
 {
     if (possibleLengths.Count != desc.PossibleLengthCount)
         return false;
     // Note that both should be sorted already, and we know they are the same length.
     var i = 0;
     foreach (var length in possibleLengths)
     {
         if (length != desc.PossibleLengthList[i])
             return false;
         i++;
     }
     return true;
 }
 /**
  * Sets the possible length fields in the metadata from the sets of data passed in. Checks that
  * the length is covered by the "parent" phone number description element if one is present, and
  * if the lengths are exactly the same as this, they are not filled in for efficiency reasons.
  *
  * @param parentDesc  the "general description" element or null if desc is the generalDesc itself
  * @param desc  the PhoneNumberDesc object that we are going to set lengths for
  */
 private static void SetPossibleLengths(SortedSet <int> lengths,
                                        SortedSet <int> localOnlyLengths, PhoneNumberDesc parentDesc, PhoneNumberDesc.Builder desc)
 {
     // Only add the lengths to this sub-type if they aren't exactly the same as the possible
     // lengths in the general desc (for metadata size reasons).
     if (parentDesc == null || !ArePossibleLengthsEqual(lengths, parentDesc))
     {
         foreach (var length in lengths)
         {
             if (parentDesc == null || parentDesc.PossibleLengthList.Contains(length))
             {
                 desc.PossibleLengthList.Add(length);
             }
             else
             {
                 // We shouldn't have possible lengths defined in a child element that are not covered by
                 // the general description. We check this here even though the general description is
                 // derived from child elements because it is only derived from a subset, and we need to
                 // ensure *all* child elements have a valid possible length.
                 throw new Exception(
                           $"Out-of-range possible length found ({length}), parent lengths {string.Join(", ", parentDesc.PossibleLengthList)}.");
             }
         }
     }
     // We check that the local-only length isn't also a normal possible length (only relevant for
     // the general-desc, since within elements such as fixed-line we would throw an exception if we
     // saw this) before adding it to the collection of possible local-only lengths.
     foreach (var length in localOnlyLengths)
     {
         if (!lengths.Contains(length))
         {
             // We check it is covered by either of the possible length sets of the parent
             // PhoneNumberDesc, because for example 7 might be a valid localOnly length for mobile, but
             // a valid national length for fixedLine, so the generalDesc would have the 7 removed from
             // localOnly.
             if (parentDesc == null || parentDesc.PossibleLengthLocalOnlyList.Contains(length) ||
                 parentDesc.PossibleLengthList.Contains(length))
             {
                 desc.PossibleLengthLocalOnlyList.Add(length);
             }
             else
             {
                 throw new Exception(
                           $"Out-of-range local-only possible length found ({length}), parent length {string.Join(", ", parentDesc.PossibleLengthLocalOnlyList)}.");
             }
         }
     }
 }
        /**
         * Processes a phone number description element from the XML file and returns it as a
         * PhoneNumberDesc. If the description element is a fixed line or mobile number, the general
         * description will be used to fill in the whole element if necessary, or any components that are
         * missing. For all other types, the general description will only be used to fill in missing
         * components if the type has a partial definition. For example, if no "tollFree" element exists,
         * we assume there are no toll free numbers for that locale, and return a phone number description
         * with "NA" for both the national and possible number patterns.
         *
         * @param generalDesc  a generic phone number description that will be used to fill in missing
         *                     parts of the description
         * @param countryElement  the XML element representing all the country information
         * @param numberType  the name of the number type, corresponding to the appropriate tag in the XML
         *                    file with information about that type
         * @return  complete description of that phone number type
         */

        public static PhoneNumberDesc ProcessPhoneNumberDescElement(PhoneNumberDesc generalDesc,
                                                                    XElement countryElement, String numberType, bool liteBuild)
        {
            if (generalDesc == null)
            {
                generalDesc = new PhoneNumberDesc.Builder().Build();
            }
            var phoneNumberDescList = countryElement.GetElementsByTagName(numberType);
            var numberDesc          = new PhoneNumberDesc.Builder();

            if (phoneNumberDescList.Length == 0 && !IsValidNumberType(numberType))
            {
                numberDesc.SetNationalNumberPattern("NA");
                numberDesc.SetPossibleNumberPattern("NA");
                return(numberDesc.Build());
            }
            numberDesc.MergeFrom(generalDesc);
            if (phoneNumberDescList.Length > 0)
            {
                XElement element         = phoneNumberDescList[0];
                var      possiblePattern = element.GetElementsByTagName(POSSIBLE_NUMBER_PATTERN);
                if (possiblePattern.Length > 0)
                {
                    numberDesc.SetPossibleNumberPattern(ValidateRE(possiblePattern[0].Value, true));
                }

                var validPattern = element.GetElementsByTagName(NATIONAL_NUMBER_PATTERN);
                if (validPattern.Length > 0)
                {
                    numberDesc.SetNationalNumberPattern(ValidateRE(validPattern[0].Value, true));
                }

                if (!liteBuild)
                {
                    var exampleNumber = element.GetElementsByTagName(EXAMPLE_NUMBER);
                    if (exampleNumber.Length > 0)
                    {
                        numberDesc.SetExampleNumber(exampleNumber[0].Value);
                    }
                }
            }
            return(numberDesc.Build());
        }
        /**
         * Processes a phone number description element from the XML file and returns it as a
         * PhoneNumberDesc. If the description element is a fixed line or mobile number, the parent
         * description will be used to fill in the whole element if necessary, or any components that are
         * missing. For all other types, the parent description will only be used to fill in missing
         * components if the type has a partial definition. For example, if no "tollFree" element exists,
         * we assume there are no toll free numbers for that locale, and return a phone number description
         * with no national number data and [-1] for the possible lengths. Note that the parent
         * description must therefore already be processed before this method is called on any child
         * elements.
         *
         * @param generalDesc  a generic phone number description that will be used to fill in missing
         *                     parts of the description
         * @param countryElement  the XML element representing all the country information
         * @param numberType  the name of the number type, corresponding to the appropriate tag in the XML
         *                    file with information about that type
         * @return  complete description of that phone number type
         */
        public static PhoneNumberDesc.Builder ProcessPhoneNumberDescElement(PhoneNumberDesc parentDesc,
                                                                            XElement countryElement, string numberType)
        {
            var phoneNumberDescList = countryElement.Elements(numberType).ToList();
            var numberDesc          = new PhoneNumberDesc.Builder();

            if (phoneNumberDescList.Count == 0)
            {
                // -1 will never match a possible phone number length, so is safe to use to ensure this never
                // matches. We don't leave it empty, since for compression reasons, we use the empty list to
                // mean that the generalDesc possible lengths apply.
                numberDesc.AddPossibleLength(-1);
                return(numberDesc);
            }
            if (phoneNumberDescList.Count > 1)
            {
                throw new Exception($"Multiple elements with type {numberType} found.");
            }
            var element = phoneNumberDescList[0];

            parentDesc ??= new PhoneNumberDesc();
            var lengths          = new SortedSet <int>();
            var localOnlyLengths = new SortedSet <int>();

            PopulatePossibleLengthSets(element.Elements(POSSIBLE_LENGTHS), lengths, localOnlyLengths);
            SetPossibleLengths(lengths, localOnlyLengths, parentDesc, numberDesc);

            var validPattern = element.Element(NATIONAL_NUMBER_PATTERN);

            if (validPattern != null)
            {
                numberDesc.SetNationalNumberPattern(ValidateRE(validPattern.Value, true));
            }

            var exampleNumber = element.Element(EXAMPLE_NUMBER);

            if (exampleNumber != null)
            {
                numberDesc.SetExampleNumber(exampleNumber.Value);
            }

            return(numberDesc);
        }
Beispiel #9
0
        private PhoneNumberDesc GetFiltered(string type, PhoneNumberDesc desc)
        {
            var builder = new PhoneNumberDesc.Builder().MergeFrom(desc);

            if (ShouldDrop(type, "nationalNumberPattern"))
            {
                builder.ClearNationalNumberPattern();
            }
            if (ShouldDrop(type, "possibleLength"))
            {
                builder.ClearPossibleLength();
            }
            if (ShouldDrop(type, "possibleLengthLocalOnly"))
            {
                builder.ClearPossibleLengthLocalOnly();
            }
            if (ShouldDrop(type, "exampleNumber"))
            {
                builder.ClearExampleNumber();
            }
            return(builder.Build());
        }
Beispiel #10
0
        /**
         * Tests whether a short number matches a valid pattern in a region. Note that this doesn't verify
         * the number is actually in use, which is impossible to tell by just looking at the number
         * itself.
         *
         * @param number the short number for which we want to test the validity
         * @param regionDialingFrom the region from which the number is dialed
         * @return whether the short number matches a valid pattern
         */
        public bool isValidShortNumberForRegion(PhoneNumber number, string regionDialingFrom)
        {
            if (!RegionDialingFromMatchesNumber(number, regionDialingFrom))
            {
                return(false);
            }
            PhoneMetadata phoneMetadata =
                MetadataManager.GetShortNumberMetadataForRegion(regionDialingFrom);

            if (phoneMetadata == null)
            {
                return(false);
            }
            string          shortNumber = GetNationalSignificantNumber(number);
            PhoneNumberDesc generalDesc = phoneMetadata.GeneralDesc;

            if (!MatchesPossibleNumberAndNationalNumber(shortNumber, generalDesc))
            {
                return(false);
            }
            PhoneNumberDesc shortNumberDesc = phoneMetadata.ShortCode;

            return(MatchesPossibleNumberAndNationalNumber(shortNumber, shortNumberDesc));
        }
 public Builder MergeFrom(PhoneNumberDesc other)
 {
     if (other == global::PhoneNumbers.PhoneNumberDesc.DefaultInstance) return this;
     if (other.HasNationalNumberPattern) {
       NationalNumberPattern = other.NationalNumberPattern;
     }
     if (other.HasPossibleNumberPattern) {
       PossibleNumberPattern = other.PossibleNumberPattern;
     }
     if (other.possibleLength_.Count != 0) {
        result.possibleLength_.AddRange(other.possibleLength_);
     }
     if (other.possibleLengthLocalOnly_.Count != 0) {
        result.possibleLengthLocalOnly_.AddRange(other.possibleLengthLocalOnly_);
     }
     if (other.HasExampleNumber) {
       ExampleNumber = other.ExampleNumber;
     }
     return this;
 }
 public Builder Clear()
 {
     result = new PhoneNumberDesc();
     return this;
 }
            public PhoneNumberDesc BuildPartial()
            {
                if (result == null) {
                  throw new global::System.InvalidOperationException("build() has already been called on this Builder");
                }

                PhoneNumberDesc returnMe = result;
                result = null;
                return returnMe;
            }
 public static Builder CreateBuilder(PhoneNumberDesc prototype)
 {
     return (Builder) new Builder().MergeFrom(prototype);
 }
Beispiel #15
0
 public static Builder CreateBuilder(PhoneNumberDesc prototype)
 {
     return(new Builder().MergeFrom(prototype));
 }
        /**
        * Processes a phone number description element from the XML file and returns it as a
        * PhoneNumberDesc. If the description element is a fixed line or mobile number, the general
        * description will be used to fill in the whole element if necessary, or any components that are
        * missing. For all other types, the general description will only be used to fill in missing
        * components if the type has a partial definition. For example, if no "tollFree" element exists,
        * we assume there are no toll free numbers for that locale, and return a phone number description
        * with "NA" for both the national and possible number patterns.
        *
        * @param generalDesc  a generic phone number description that will be used to fill in missing
        *                     parts of the description
        * @param countryElement  the XML element representing all the country information
        * @param numberType  the name of the number type, corresponding to the appropriate tag in the XML
        *                    file with information about that type
        * @return  complete description of that phone number type
        */
        public static PhoneNumberDesc ProcessPhoneNumberDescElement(PhoneNumberDesc generalDesc,
            XmlElement countryElement, String numberType, bool liteBuild)
        {
            if (generalDesc == null)
                generalDesc = new PhoneNumberDesc.Builder().Build();
            var phoneNumberDescList = countryElement.GetElementsByTagName(numberType);
            var numberDesc = new PhoneNumberDesc.Builder();
            if (phoneNumberDescList.Count == 0 && !IsValidNumberType(numberType))
            {
                numberDesc.SetNationalNumberPattern("NA");
                numberDesc.SetPossibleNumberPattern("NA");
                return numberDesc.Build();
            }
            numberDesc.MergeFrom(generalDesc);
            if (phoneNumberDescList.Count > 0)
            {
                XmlElement element = (XmlElement)phoneNumberDescList[0];
                var possiblePattern = element.GetElementsByTagName(POSSIBLE_NUMBER_PATTERN);
                if (possiblePattern.Count > 0)
                    numberDesc.SetPossibleNumberPattern(ValidateRE(possiblePattern[0].InnerText, true));

                var validPattern = element.GetElementsByTagName(NATIONAL_NUMBER_PATTERN);
                if (validPattern.Count > 0)
                    numberDesc.SetNationalNumberPattern(ValidateRE(validPattern[0].InnerText, true));

                if (!liteBuild)
                {
                    var exampleNumber = element.GetElementsByTagName(EXAMPLE_NUMBER);
                    if (exampleNumber.Count > 0)
                        numberDesc.SetExampleNumber(exampleNumber[0].InnerText);
                }
            }
            return numberDesc.Build();
        }
 private bool IsNumberMatchingDesc(String nationalNumber, PhoneNumberDesc numberDesc)
 {
     var possibleNumberPatternMatch = regexCache.GetPatternForRegex(
         numberDesc.PossibleNumberPattern).MatchAll(nationalNumber);
     var nationalNumberPatternMatch = regexCache.GetPatternForRegex(
         numberDesc.NationalNumberPattern).MatchAll(nationalNumber);
     return possibleNumberPatternMatch.Success && nationalNumberPatternMatch.Success;
 }
 public Builder MergeFrom(PhoneNumberDesc other)
 {
     if (other == global::PhoneNumbers.PhoneNumberDesc.DefaultInstance) return this;
     if (other.HasNationalNumberPattern) {
       NationalNumberPattern = other.NationalNumberPattern;
     }
     if (other.HasPossibleNumberPattern) {
       PossibleNumberPattern = other.PossibleNumberPattern;
     }
     if (other.HasExampleNumber) {
       ExampleNumber = other.ExampleNumber;
     }
     return this;
 }