From c6fde0103c8d7d8e00a9dcfa28062bc341028fd0 Mon Sep 17 00:00:00 2001 From: Paween Itthipalkul <398585+paween@users.noreply.github.com> Date: Fri, 1 Dec 2017 13:55:40 -0800 Subject: [PATCH] Add support for short number and emegerncy number in libPhoneNumber-iOS This is a port of ShortNumberInfo class from Java version of libPhoneNumber into a category on NBPhoneNumberUtil class --- libPhoneNumber.xcodeproj/project.pbxproj | 8 +++ libPhoneNumber/Internal/NBRegExMatcher.m | 8 +++ .../Internal/NBRegularExpressionCache.m | 4 ++ libPhoneNumber/NBMetadataHelper.m | 63 +++++++++++++++++++ .../NBPhoneNumberUtil+ShortNumberTestHelper.h | 29 +++++++++ .../NBPhoneNumberUtil+ShortNumberTestHelper.m | 53 ++++++++++++++++ 6 files changed, 165 insertions(+) create mode 100644 libPhoneNumberTests/NBPhoneNumberUtil+ShortNumberTestHelper.h create mode 100644 libPhoneNumberTests/NBPhoneNumberUtil+ShortNumberTestHelper.m diff --git a/libPhoneNumber.xcodeproj/project.pbxproj b/libPhoneNumber.xcodeproj/project.pbxproj index 9566f37..b8dee8d 100755 --- a/libPhoneNumber.xcodeproj/project.pbxproj +++ b/libPhoneNumber.xcodeproj/project.pbxproj @@ -37,6 +37,8 @@ 0F4D824C1FCF60A5009F9C17 /* NBShortNumberInfoTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0F4D824B1FCF60A5009F9C17 /* NBShortNumberInfoTest.m */; }; 0F58330B1FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5833091FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTest.h */; }; 0F58330D1FD1FD1400F26ED4 /* NBPhoneNumberUtil+ShortNumberTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0F58330A1FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTest.m */; }; + 0F58330B1FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTestHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5833091FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTestHelper.h */; }; + 0F58330D1FD1FD1400F26ED4 /* NBPhoneNumberUtil+ShortNumberTestHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 0F58330A1FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTestHelper.m */; }; 1485C5271E06F4890092F541 /* NBAsYouTypeFormatterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1485C5231E06F4890092F541 /* NBAsYouTypeFormatterTest.m */; }; 1485C5291E06F4890092F541 /* NBPhoneNumberUtilTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1485C5251E06F4890092F541 /* NBPhoneNumberUtilTest.m */; }; 14B7A2AB1DE9BF160051AED7 /* NBMetadataHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = FD12C2691A87401B00B53856 /* NBMetadataHelper.m */; }; @@ -181,6 +183,8 @@ 0F4D824B1FCF60A5009F9C17 /* NBShortNumberInfoTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NBShortNumberInfoTest.m; sourceTree = ""; }; 0F5833091FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NBPhoneNumberUtil+ShortNumberTest.h"; sourceTree = ""; }; 0F58330A1FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NBPhoneNumberUtil+ShortNumberTest.m"; sourceTree = ""; }; + 0F5833091FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTestHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NBPhoneNumberUtil+ShortNumberTestHelper.h"; sourceTree = ""; }; + 0F58330A1FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTestHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NBPhoneNumberUtil+ShortNumberTestHelper.m"; sourceTree = ""; }; 0F58330E1FD2004A00F26ED4 /* NBPhoneNumberUtil+Category.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NBPhoneNumberUtil+Category.h"; sourceTree = ""; }; 1485C5231E06F4890092F541 /* NBAsYouTypeFormatterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NBAsYouTypeFormatterTest.m; path = libPhoneNumberTests/NBAsYouTypeFormatterTest.m; sourceTree = SOURCE_ROOT; }; 1485C5251E06F4890092F541 /* NBPhoneNumberUtilTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NBPhoneNumberUtilTest.m; path = libPhoneNumberTests/NBPhoneNumberUtilTest.m; sourceTree = SOURCE_ROOT; }; @@ -352,6 +356,8 @@ 0F4D824B1FCF60A5009F9C17 /* NBShortNumberInfoTest.m */, 0F5833091FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTest.h */, 0F58330A1FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTest.m */, + 0F5833091FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTestHelper.h */, + 0F58330A1FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTestHelper.m */, ); name = libPhoneNumber.tests; path = libPhoneNumberTests; @@ -593,6 +599,7 @@ files = ( 8B1FEFA01EB7BFC500FBDE87 /* NBGeneratedPhoneNumberMetaData.h in Headers */, 0F58330B1FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTest.h in Headers */, + 0F58330B1FD1FC9500F26ED4 /* NBPhoneNumberUtil+ShortNumberTestHelper.h in Headers */, 0F2870981FCF8F13006230BF /* NBRegExMatcher.h in Headers */, 34ACBBB61B7124AB0064B3BD /* NBPhoneNumberDefines.h in Headers */, 34ACBBBD1B7125450064B3BD /* NBAsYouTypeFormatter.h in Headers */, @@ -895,6 +902,7 @@ 14B7A2B41DE9BF160051AED7 /* NBPhoneNumberDefines.m in Sources */, 1485C5271E06F4890092F541 /* NBAsYouTypeFormatterTest.m in Sources */, 0F58330D1FD1FD1400F26ED4 /* NBPhoneNumberUtil+ShortNumberTest.m in Sources */, + 0F58330D1FD1FD1400F26ED4 /* NBPhoneNumberUtil+ShortNumberTestHelper.m in Sources */, 14B7A2B51DE9BF160051AED7 /* NBPhoneNumberUtil.m in Sources */, 0F2870AF1FCF961C006230BF /* NBRegExMatcher.m in Sources */, 14B7A2B61DE9BF160051AED7 /* NBAsYouTypeFormatter.m in Sources */, diff --git a/libPhoneNumber/Internal/NBRegExMatcher.m b/libPhoneNumber/Internal/NBRegExMatcher.m index c560314..12f197e 100644 --- a/libPhoneNumber/Internal/NBRegExMatcher.m +++ b/libPhoneNumber/Internal/NBRegExMatcher.m @@ -52,7 +52,11 @@ NSTextCheckingResult *prefixResult = [prefixRegEx firstMatchInString:string options:NSMatchingAnchored range:wholeStringRange]; +<<<<<<< HEAD if (prefixResult.numberOfRanges < 1) { +======= + if (prefixResult.numberOfRanges <= 0) { +>>>>>>> Add support for short number and emegerncy number in libPhoneNumber-iOS // No prefix match found. return NO; } else { @@ -62,11 +66,15 @@ options:NSMatchingAnchored range:wholeStringRange]; +<<<<<<< HEAD if (exactResult.numberOfRanges > 0) { return YES; } else { return allowsPrefixMatch; } +======= + return (allowsPrefixMatch || exactResult.numberOfRanges > 0) +>>>>>>> Add support for short number and emegerncy number in libPhoneNumber-iOS } } diff --git a/libPhoneNumber/Internal/NBRegularExpressionCache.m b/libPhoneNumber/Internal/NBRegularExpressionCache.m index 39cae81..b2d0290 100644 --- a/libPhoneNumber/Internal/NBRegularExpressionCache.m +++ b/libPhoneNumber/Internal/NBRegularExpressionCache.m @@ -46,7 +46,11 @@ NSRegularExpression *regEx = [[NSRegularExpression alloc] initWithPattern:pattern options:kNilOptions error:&error]; +<<<<<<< HEAD if (regEx == nil && error != nil) { +======= + if (regEx == nil || error != nil) { +>>>>>>> Add support for short number and emegerncy number in libPhoneNumber-iOS NSLog(@"An error parsing a regular expression: %@", error); return nil; } diff --git a/libPhoneNumber/NBMetadataHelper.m b/libPhoneNumber/NBMetadataHelper.m index abbad3d..d548618 100644 --- a/libPhoneNumber/NBMetadataHelper.m +++ b/libPhoneNumber/NBMetadataHelper.m @@ -256,4 +256,67 @@ static NSString *StringByTrimming(NSString *aString) { #endif // SHORT_NUMBER_SUPPORT +#if SHORT_NUMBER_SUPPORT + ++ (NSDictionary *)shortNumberDataMap { + static NSDictionary *shortNumberDataDictionary; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // Data is a gzipped JSON file that is embedded in the binary. + // See GeneratePhoneNumberHeader.sh and PhoneNumberMetaData.h for details. + NSMutableData* gunzippedData = + [NSMutableData dataWithLength:kShortNumberMetaDataExpandedLength]; + + z_stream zStream; + memset(&zStream, 0, sizeof(zStream)); + __attribute((unused)) int err = inflateInit2(&zStream, 16); + NSAssert(err == Z_OK, @"Unable to init stream. err = %d", err); + + zStream.next_in = kShortNumberMetaData; + zStream.avail_in = (uint)kShortNumberMetaDataCompressedLength; + zStream.next_out = (Bytef *)gunzippedData.bytes; + zStream.avail_out = (uint)gunzippedData.length; + + err = inflate(&zStream, Z_FINISH); + NSAssert(err == Z_STREAM_END, @"Unable to inflate compressed data. err = %d", err); + + err = inflateEnd(&zStream); + NSAssert(err == Z_OK, @"Unable to inflate compressed data. err = %d", err); + + NSError *error = nil; + shortNumberDataDictionary = [NSJSONSerialization JSONObjectWithData:gunzippedData + options:0 + error:&error]; + NSAssert(error == nil, @"Unable to convert JSON - %@", error); + }); + return shortNumberDataDictionary; +} + +- (NBPhoneMetaData *)shortNumberMetadataForRegion:(NSString *)regionCode +{ + regionCode = StringByTrimming(regionCode); + if (regionCode.length == 0) { + return nil; + } + + regionCode = [regionCode uppercaseString]; + + if ([_cachedShortNumberMetaDataKey isEqualToString:regionCode]) { + return _cachedShortNumberMetadata; + } + + NSDictionary *dict = [[self class] shortNumberDataMap][@"countryToMetadata"]; + NSArray *entry = dict[regionCode]; + if (entry) { + NBPhoneMetaData *metadata = [[NBPhoneMetaData alloc] initWithEntry:entry]; + _cachedShortNumberMetadata = metadata; + _cachedShortNumberMetaDataKey = regionCode; + return metadata; + } + + return nil; +} + +#endif // SHORT_NUMBER_SUPPORT + @end diff --git a/libPhoneNumberTests/NBPhoneNumberUtil+ShortNumberTestHelper.h b/libPhoneNumberTests/NBPhoneNumberUtil+ShortNumberTestHelper.h new file mode 100644 index 0000000..7bf3fb6 --- /dev/null +++ b/libPhoneNumberTests/NBPhoneNumberUtil+ShortNumberTestHelper.h @@ -0,0 +1,29 @@ +// +// NBPhoneNumberUtil+ShortNumberTestHelper.h +// libPhoneNumber +// +// Created by Paween Itthipalkul on 12/1/17. +// Copyright © 2017 Google LLC. All rights reserved. +// + +#import +#import "NBPhoneNumberUtil.h" +#import "NBPhoneNumberUtil+ShortNumber.h" + +#if SHORT_NUMBER_SUPPORT + +NS_ASSUME_NONNULL_BEGIN + +/** + Includes methods used only for testing NBPhoneNumberUtil+ShortNumber. + */ +@interface NBPhoneNumberUtil(ShortNumberTestHelper) + +- (NSString *)exampleShortNumberForCost:(NBEShortNumberCost)cost regionCode:(NSString *)regionCode; +- (NSString *)exampleShortNumberWithRegionCode:(NSString *)regionCode; + +@end + +NS_ASSUME_NONNULL_END + +#endif // SHORT_NUMBER_SUPPORT diff --git a/libPhoneNumberTests/NBPhoneNumberUtil+ShortNumberTestHelper.m b/libPhoneNumberTests/NBPhoneNumberUtil+ShortNumberTestHelper.m new file mode 100644 index 0000000..29bb1cf --- /dev/null +++ b/libPhoneNumberTests/NBPhoneNumberUtil+ShortNumberTestHelper.m @@ -0,0 +1,53 @@ +// +// NBPhoneNumberUtil+ShortNumberTestHelper.m +// libPhoneNumber +// +// Created by Paween Itthipalkul on 12/1/17. +// Copyright © 2017 Google LLC. All rights reserved. +// + +#import "NBPhoneNumberUtil+ShortNumberTestHelper.h" + +#import "NBMetadataHelper.h" +#import "NBPhoneMetadata.h" +#import "NBPhoneNumberDesc.h" +#import "NBPhoneNumberUtil+Category.h" + +#if SHORT_NUMBER_SUPPORT + +@implementation NBPhoneNumberUtil(ShortNumberTestHelper) + +- (NSString *)exampleShortNumberForCost:(NBEShortNumberCost)cost regionCode:(NSString *)regionCode { + NBPhoneMetaData *metadata = [self.helper shortNumberMetadataForRegion:regionCode]; + if (metadata == nil) { + return @""; + } + + NBPhoneNumberDesc *desc = nil; + switch (cost) { + case NBEShortNumberCostTollFree: + desc = metadata.tollFree; + break; + case NBEShortNumberCostPremiumRate: + desc = metadata.premiumRate; + break; + case NBEShortNumberCostStandardRate: + desc = metadata.standardRate; + break; + case NBEShortNumberCostUnknown: + // UNKNOWN_COST numbers are computed by the process of elimination from the other cost + // categories. + break; + } + + return desc.exampleNumber ?: @""; +} + +- (NSString *)exampleShortNumberWithRegionCode:(NSString *)regionCode { + NBPhoneMetaData *metadata = [self.helper shortNumberMetadataForRegion:regionCode]; + return metadata.shortCode.exampleNumber ?: @""; +} + +@end + +#endif // SHORT_NUMBER_SUPPORT