Compare commits

..

No commits in common. "signal-master" and "master" have entirely different histories.

67 changed files with 14876 additions and 56427 deletions

1
.coveralls.yml Normal file
View File

@ -0,0 +1 @@
service_name: travis-ci

12
.slather.yml Normal file
View File

@ -0,0 +1,12 @@
ci_service: travis_ci
coverage_service: coveralls
xcodeproj: libPhoneNumber.xcodeproj
ignore:
- libPhoneNumber/AppDelegate.m
- libPhoneNumber/main.m
- libPhoneNumber/NBPhoneMetaDataGenerator.m
- libPhoneNumber/NBPhoneMetaData.m
- libPhoneNumber/NBPhoneNumberDesc.m
- libPhoneNumber/NBMetadataHelper.m
- libPhoneNumber/NBNumberFormat.m
- libPhoneNumber/NBPhoneNumber.m

11
.travis.yml Normal file
View File

@ -0,0 +1,11 @@
language: objective-c
before_install:
- gem install slather -N
script:
- xcodebuild -project libPhoneNumber.xcodeproj -scheme libPhoneNumberiOSTests clean
- xcodebuild -project libPhoneNumber.xcodeproj -scheme libPhoneNumberiOSTests -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES build-for-testing
- xctool -project libPhoneNumber.xcodeproj -scheme libPhoneNumberiOSTests run-tests -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES
after_success: slather

View File

@ -1,3 +0,0 @@
.PHONY: metadata
metadata:
swift run --package-path MetadataArchiver -c release MetadataArchiver ${LIBPHONENUMBER}

View File

@ -1,8 +0,0 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

View File

@ -1,9 +0,0 @@
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "MetadataArchiver",
platforms: [.macOS(.v15)],
targets: [.executableTarget(name: "MetadataArchiver")]
)

View File

@ -1,64 +0,0 @@
import Foundation
import JavaScriptCore
func printErr(_ value: String) {
try! FileHandle.standardError.write(contentsOf: Data(value.utf8) + Data("\n".utf8))
}
if CommandLine.arguments.count < 2 {
printErr("You must specify a path to libphonenumber.")
exit(1)
}
let libPhoneNumberPath = CommandLine.arguments[1]
let libPhoneNumberURL = URL(filePath: libPhoneNumberPath, relativeTo: URL.currentDirectory())
let outputUrl = URL(filePath: "libPhoneNumber/NBPhoneNumberMetaData.plist", relativeTo: URL.currentDirectory())
// Dump JSON as well to make diffs easier to review.
let jsonOutputUrl = URL(filePath: "libPhoneNumber/NBPhoneNumberMetaData.json", relativeTo: URL.currentDirectory())
func archiveObject(_ object: Any) -> Data {
class Deduplicator: NSObject, NSKeyedArchiverDelegate {
var objects: Set<NSObject> = []
func archiver(_ archiver: NSKeyedArchiver, willEncode object: Any) -> Any? {
guard let nsObject = object as? NSObject else {
return object
}
return objects.insert(nsObject).memberAfterInsert
}
}
let coder = NSKeyedArchiver(requiringSecureCoding: false)
let delegate = Deduplicator()
coder.delegate = delegate
coder.encode(object, forKey: NSKeyedArchiveRootObjectKey)
_ = delegate
return coder.encodedData
}
func parseMetadata3() throws {
let context = JSContext()!
context.exceptionHandler = { _, exception in
printErr("\(exception!)")
exit(1)
}
context.evaluateScript("""
var goog = {"provide": function() {}};
var i18n = {"phonenumbers": {"metadata": {}}};
""")
let metadataFileUrl = libPhoneNumberURL.appending(path: "javascript/i18n/phonenumbers/metadata.js")
let metadataContent = String(data: try Data(contentsOf: metadataFileUrl), encoding: .utf8)!
context.evaluateScript(metadataContent)
let metadataEncoded = context.evaluateScript("JSON.stringify(i18n.phonenumbers.metadata)").toString()!
let metadataObject = try JSONSerialization.jsonObject(with: Data(metadataEncoded.utf8))
try JSONSerialization.data(withJSONObject: metadataObject, options: [.sortedKeys, .prettyPrinted]).write(to: jsonOutputUrl)
try archiveObject(metadataObject).write(to: outputUrl)
}
do {
try parseMetadata3()
} catch {
printErr("\(error)")
exit(1)
}

181
README.md Normal file → Executable file
View File

@ -1,17 +1,174 @@
# Signal's fork of [libPhoneNumber-iOS][]
[![CocoaPods](https://img.shields.io/cocoapods/p/libPhoneNumber-iOS.svg?style=flat)](http://cocoapods.org/?q=libPhoneNumber-iOS)
[![CocoaPods](https://img.shields.io/cocoapods/v/libPhoneNumber-iOS.svg?style=flat)](http://cocoapods.org/?q=libPhoneNumber-iOS)
[![Travis](https://travis-ci.org/iziz/libPhoneNumber-iOS.svg?branch=master)](https://travis-ci.org/iziz/libPhoneNumber-iOS)
[![Coveralls](https://coveralls.io/repos/iziz/libPhoneNumber-iOS/badge.svg?branch=master&service=github)](https://coveralls.io/github/iziz/libPhoneNumber-iOS?branch=master)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
This is Signal's fork of libPhoneNumber-iOS, which is an Objective-C port of [Google's libphonenumber][libphonenumber].
# **libPhoneNumber for iOS**
## How to update metadata from libphonenumber
- NBPhoneNumberUtil
- NBAsYouTypeFormatter
- NBTextField.swift (Swift 3)
If you want the latest metadata from libphonenumber...
> ARC only, or add the **"-fobjc-arc"** flag for non-ARC
1. Clone this fork.
1. Check out the version of [libphonenumber][] (not libPhoneNumber-iOS) that you want to pull metadata from. Remember this `<path>`.
1. From the project root, run `LIBPHONENUMBER=<path> make metadata`. Use the `<path>` you remembered in the prior step.
1. Commit the changes to the `signal-master` branch and push the changes.
1. Update the dependency in the [Signal iOS project][signal-ios] as normal (using `bundle exec pod update libPhoneNumber-iOS`).
## Update Log
[https://github.com/iziz/libPhoneNumber-iOS/wiki/Update-Log](https://github.com/iziz/libPhoneNumber-iOS/wiki/Update-Log)
[libPhoneNumber-iOS]: https://github.com/iziz/libPhoneNumber-iOS
[libphonenumber]: https://github.com/google/libphonenumber
[signal-ios]: https://github.com/signalapp/Signal-iOS
## Issue
You can check phone number validation using below link.
https://rawgit.com/googlei18n/libphonenumber/master/javascript/i18n/phonenumbers/demo-compiled.html
Please report, if the above results are different from this iOS library.
Otherwise, please create issue to following link below to request additional telephone numbers formatting rule.
https://github.com/google/libphonenumber/issues
Metadata in this library was generated from that. so, you should change it first. :)
## Install
#### Using [CocoaPods](http://cocoapods.org/?q=libPhoneNumber-iOS)
```
source 'https://github.com/CocoaPods/Specs.git'
pod 'libPhoneNumber-iOS', '~> 0.8'
```
#### Using [Carthage](https://github.com/Carthage/Carthage)
Carthage is a decentralized dependency manager that automates the process of adding frameworks to your Cocoa application.
You can install Carthage with [Homebrew](http://brew.sh/) using the following command:
```bash
$ brew update
$ brew install carthage
```
To integrate libPhoneNumber into your Xcode project using Carthage, specify it in your `Cartfile`:
```ogdl
github "iziz/libPhoneNumber-iOS"
```
And set the **Embedded Content Contains Swift** to "Yes" in your build settings.
#### Setting up manually
Add source files to your projects from libPhoneNumber
- Add "CoreTelephony.framework"
See sample test code from
> [libPhoneNumber-iOS/libPhoneNumberTests/ ... Test.m] (https://github.com/iziz/libPhoneNumber-iOS/tree/master/libPhoneNumberTests)
## Usage - **NBPhoneNumberUtil**
```obj-c
NBPhoneNumberUtil *phoneUtil = [[NBPhoneNumberUtil alloc] init];
NSError *anError = nil;
NBPhoneNumber *myNumber = [phoneUtil parse:@"6766077303"
defaultRegion:@"AT" error:&anError];
if (anError == nil) {
NSLog(@"isValidPhoneNumber ? [%@]", [phoneUtil isValidNumber:myNumber] ? @"YES":@"NO");
// E164 : +436766077303
NSLog(@"E164 : %@", [phoneUtil format:myNumber
numberFormat:NBEPhoneNumberFormatE164
error:&anError]);
// INTERNATIONAL : +43 676 6077303
NSLog(@"INTERNATIONAL : %@", [phoneUtil format:myNumber
numberFormat:NBEPhoneNumberFormatINTERNATIONAL
error:&anError]);
// NATIONAL : 0676 6077303
NSLog(@"NATIONAL : %@", [phoneUtil format:myNumber
numberFormat:NBEPhoneNumberFormatNATIONAL
error:&anError]);
// RFC3966 : tel:+43-676-6077303
NSLog(@"RFC3966 : %@", [phoneUtil format:myNumber
numberFormat:NBEPhoneNumberFormatRFC3966
error:&anError]);
} else {
NSLog(@"Error : %@", [anError localizedDescription]);
}
NSLog (@"extractCountryCode [%@]", [phoneUtil extractCountryCode:@"823213123123" nationalNumber:nil]);
NSString *nationalNumber = nil;
NSNumber *countryCode = [phoneUtil extractCountryCode:@"823213123123" nationalNumber:&nationalNumber];
NSLog (@"extractCountryCode [%@] [%@]", countryCode, nationalNumber);
```
##### Output
```
2014-07-06 12:39:37.240 libPhoneNumberTest[1581:60b] isValidPhoneNumber ? [YES]
2014-07-06 12:39:37.242 libPhoneNumberTest[1581:60b] E164 : +436766077303
2014-07-06 12:39:37.243 libPhoneNumberTest[1581:60b] INTERNATIONAL : +43 676 6077303
2014-07-06 12:39:37.243 libPhoneNumberTest[1581:60b] NATIONAL : 0676 6077303
2014-07-06 12:39:37.244 libPhoneNumberTest[1581:60b] RFC3966 : tel:+43-676-6077303
2014-07-06 12:39:37.244 libPhoneNumberTest[1581:60b] extractCountryCode [82]
2014-07-06 12:39:37.245 libPhoneNumberTest[1581:60b] extractCountryCode [82] [3213123123]
```
#### with Swift
##### Case (1) with Framework
```
import libPhoneNumberiOS
```
##### Case (2) with Bridging-Header
```obj-c
// Manually added
#import "NBPhoneNumberUtil.h"
#import "NBPhoneNumber.h"
// CocoaPods (check your library path)
#import "libPhoneNumber_iOS/NBPhoneNumberUtil.h"
#import "libPhoneNumber_iOS/NBPhoneNumber.h"
// add more if you want...
```
##### Case (3) with CocoaPods
import libPhoneNumber_iOS
##### - in swift class file
###### 2.x
```swift
override func viewDidLoad() {
super.viewDidLoad()
let phoneUtil = NBPhoneNumberUtil()
do {
let phoneNumber: NBPhoneNumber = try phoneUtil.parse("01065431234", defaultRegion: "KR")
let formattedString: String = try phoneUtil.format(phoneNumber, numberFormat: .E164)
NSLog("[%@]", formattedString)
}
catch let error as NSError {
print(error.localizedDescription)
}
}
```
## Usage - **NBAsYouTypeFormatter**
```obj-c
NBAsYouTypeFormatter *f = [[NBAsYouTypeFormatter alloc] initWithRegionCode:@"US"];
NSLog(@"%@", [f inputDigit:@"6"]); // "6"
NSLog(@"%@", [f inputDigit:@"5"]); // "65"
NSLog(@"%@", [f inputDigit:@"0"]); // "650"
NSLog(@"%@", [f inputDigit:@"2"]); // "650 2"
NSLog(@"%@", [f inputDigit:@"5"]); // "650 25"
NSLog(@"%@", [f inputDigit:@"3"]); // "650 253"
// Note this is how a US local number (without area code) should be formatted.
NSLog(@"%@", [f inputDigit:@"2"]); // "650 2532"
NSLog(@"%@", [f inputDigit:@"2"]); // "650 253 22"
NSLog(@"%@", [f inputDigit:@"2"]); // "650 253 222"
NSLog(@"%@", [f inputDigit:@"2"]); // "650 253 2222"
// Can remove last digit
NSLog(@"%@", [f removeLastDigit]); // "650 253 222"
NSLog(@"%@", [f inputString:@"16502532222"]); // 1 650 253 2222
```
##### Visit [libphonenumber](https://github.com/google/libphonenumber) for more information or mail (zen.isis@gmail.com)

View File

@ -0,0 +1,46 @@
//
// AppDelegate.swift
// libPhoneNumber-SwiftDemo
//
// Created by tabby on 2015. 11. 8..
// Copyright © 2015 ohtalk.me. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2555" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2555" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="libPhoneNumberSampleSwift" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>libPhoneNumberSampleSwift</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIcons</key>
<dict/>
<key>CFBundleIcons~ipad</key>
<dict/>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,36 @@
//
// ViewController.swift
// libPhoneNumber-SwiftDemo
//
// Created by tabby on 2015. 11. 8..
// Copyright © 2015 ohtalk.me. All rights reserved.
//
import UIKit
import libPhoneNumberiOS
class ViewController: UIViewController {
let textField: UITextField = NBTextField()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.black
textField.backgroundColor = UIColor.white
textField.frame.size.width = 200
textField.frame.size.height = 25
view.addSubview(textField)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
textField.center = self.view.center
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "libPhoneNumber-iOS"
s.version = "1.2.0"
s.version = "0.9.15"
s.summary = "iOS library for parsing, formatting, storing and validating international phone numbers from libphonenumber library."
s.description = <<-DESC
libPhoneNumber for iOS
@ -10,12 +10,13 @@ DESC
s.license = 'Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
s.authors = { "iziz" => "zen.isis@gmail.com", "hyukhur" => "hyukhur@gmail.com" }
s.source = { :git => "https://github.com/iziz/libPhoneNumber-iOS.git", :tag => s.version.to_s }
s.ios.framework = 'Contacts'
s.ios.deployment_target = "12.0"
s.osx.deployment_target = "10.11"
s.watchos.deployment_target = "4.0"
s.tvos.deployment_target = "11.0"
s.libraries = 'z'
s.ios.framework = 'CoreTelephony'
s.ios.deployment_target = "6.0"
s.osx.deployment_target = "10.9"
s.watchos.deployment_target = "2.0"
s.tvos.deployment_target = "9.0"
s.requires_arc = true
s.resources = 'libPhoneNumber/NBPhoneNumberMetaData.plist'
s.source_files = 'libPhoneNumber/NBPhoneNumberDefines.{h,m}', 'libPhoneNumber/NBPhoneNumber.{h,m}', 'libPhoneNumber/NBNumberFormat.{h,m}', 'libPhoneNumber/NBPhoneNumberDesc.{h,m}', 'libPhoneNumber/NBPhoneMetaData.{h,m}', 'libPhoneNumber/NBPhoneNumberUtil.{h,m}', 'libPhoneNumber/NBMetadataHelper.{h,m}', 'libPhoneNumber/NBAsYouTypeFormatter.{h,m}', 'libPhoneNumber/NSArray+NBAdditions.{h,m}', 'libPhoneNumber/Internal/NBRegExMatcher.{h,m}', 'libPhoneNumber/Internal/NBRegularExpressionCache.{h,m}'
s.private_header_files = 'libPhoneNumber/NBGeneratedPhoneNumberMetaData.h'
s.source_files = 'libPhoneNumber/NBPhoneNumberDefines.{h,m}', 'libPhoneNumber/NBPhoneNumber.{h,m}', 'libPhoneNumber/NBNumberFormat.{h,m}', 'libPhoneNumber/NBPhoneNumberDesc.{h,m}', 'libPhoneNumber/NBPhoneMetaData.{h,m}', 'libPhoneNumber/NBPhoneNumberUtil.{h,m}', 'libPhoneNumber/NBMetadataHelper.{h,m}', 'libPhoneNumber/NBAsYouTypeFormatter.{h,m}', 'libPhoneNumber/NSArray+NBAdditions.{h,m}', 'libPhoneNumber/NBGeneratedPhoneNumberMetaData.h', 'libPhoneNumber/Internal/NBRegExMatcher.{h,m}', 'libPhoneNumber/Internal/NBRegularExpressionCache.{h,m}'
end

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>libPhoneNumberiOS</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,83 @@
//
// NBTextField.swift
// libPhoneNumber
//
// Created by tabby on 2015. 11. 7..
// Copyright © 2015 ohtalk.me. All rights reserved.
//
import libPhoneNumberiOS
open class NBTextField: UITextField
{
// MARK: Options/Variables for phone number formatting
let phoneNumberUtility: NBPhoneNumberUtil = NBPhoneNumberUtil()
var phoneNumberFormatter: NBAsYouTypeFormatter?
var shouldCheckValidationForInputText: Bool = true
var countryCode: String = "US" {//5 NSLocale.currentLocale().objectForKey(NSLocaleCountryCode) as! String {
didSet {
phoneNumberFormatter = NBAsYouTypeFormatter(regionCode: countryCode)
numberTextDidChange()
}
}
// MARK: Initialization
override init(frame: CGRect) {
super.init(frame: frame)
registerForNotifications()
phoneNumberFormatter = NBAsYouTypeFormatter(regionCode: countryCode)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: UITextField input managing
override open func deleteBackward() {
if text?.characters.last == " " {
if let indexNumberWithWhiteSpace = text?.characters.index((text?.endIndex)!, offsetBy: -1) {
text = text?.substring(to: indexNumberWithWhiteSpace)
}
return
}
super.deleteBackward()
}
// MARK: Notification for "UITextFieldTextDidChangeNotification"
fileprivate func registerForNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(NBTextField.numberTextDidChange), name: NSNotification.Name.UITextFieldTextDidChange, object: self)
}
func numberTextDidChange() {
let numbersOnly = phoneNumberUtility.normalize(text)
text = phoneNumberFormatter!.inputStringAndRememberPosition(numbersOnly)
if phoneNumberFormatter!.isSuccessfulFormatting == false && shouldCheckValidationForInputText {
shakeIt()
}
}
func shakeIt() {
let offset = self.bounds.size.width / 30
let animation = CABasicAnimation(keyPath: "position")
animation.duration = 0.07
animation.repeatCount = 2
animation.autoreverses = true
animation.fromValue = NSValue(cgPoint: CGPoint(x: self.center.x - offset, y: self.center.y))
animation.toValue = NSValue(cgPoint: CGPoint(x: self.center.x + offset, y: self.center.y))
self.layer.add(animation, forKey: "position")
}
}

View File

@ -0,0 +1,33 @@
//
// libPhoneNumber-iOS.h
// libPhoneNumber-iOS
//
// Created by Roy Marmelstein on 04/08/2015.
// Copyright (c) 2015 ohtalk.me. All rights reserved.
//
#import <UIKit/UIKit.h>
//! Project version number for libPhoneNumber-iOS.
FOUNDATION_EXPORT double libPhoneNumber_iOSVersionNumber;
//! Project version string for libPhoneNumber-iOS.
FOUNDATION_EXPORT const unsigned char libPhoneNumber_iOSVersionString[];
// In this header, you should import all the public headers of your framework
// using statements like #import <libPhoneNumber_iOS/PublicHeader.h>
#import "NBPhoneNumberDefines.h"
// Features
#import "NBAsYouTypeFormatter.h"
#import "NBPhoneNumberUtil.h"
// Metadata
#import "NBMetadataHelper.h"
// Model
#import "NBNumberFormat.h"
#import "NBPhoneMetaData.h"
#import "NBPhoneNumber.h"
#import "NBPhoneNumberDesc.h"

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 ohtalk.me. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,33 @@
//
// libPhoneNumbermacOS.h
// libPhoneNumbermacOS
//
// Created by Artem Starosvetskiy on 24/12/2016.
// Copyright © 2016 ohtalk.me. All rights reserved.
//
#import <Cocoa/Cocoa.h>
//! Project version number for libPhoneNumbermacOS.
FOUNDATION_EXPORT double libPhoneNumbermacOSVersionNumber;
//! Project version string for libPhoneNumbermacOS.
FOUNDATION_EXPORT const unsigned char libPhoneNumbermacOSVersionString[];
// In this header, you should import all the public headers of your framework
// using statements like #import <libPhoneNumbermacOS/PublicHeader.h>
#import "NBPhoneNumberDefines.h"
// Features
#import "NBAsYouTypeFormatter.h"
#import "NBPhoneNumberUtil.h"
// Metadata
#import "NBMetadataHelper.h"
// Model
#import "NBNumberFormat.h"
#import "NBPhoneMetaData.h"
#import "NBPhoneNumber.h"
#import "NBPhoneNumberDesc.h"

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>libPhoneNumbertvOS</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,33 @@
//
// libPhoneNumbertvOS.h
// libPhoneNumbertvOS
//
// Created by Jeff Kelley on 11/16/16.
// Copyright © 2016 ohtalk.me. All rights reserved.
//
#import <UIKit/UIKit.h>
//! Project version number for libPhoneNumber-tvOS.
FOUNDATION_EXPORT double libPhoneNumber_tvOSVersionNumber;
//! Project version string for libPhoneNumber-tvOS.
FOUNDATION_EXPORT const unsigned char libPhoneNumber_tvOSVersionString[];
// In this header, you should import all the public headers of your framework
// using statements like #import <libPhoneNumber_tvOS/PublicHeader.h>
#import "NBPhoneNumberDefines.h"
// Features
#import "NBAsYouTypeFormatter.h"
#import "NBPhoneNumberUtil.h"
// Metadata
#import "NBMetadataCore.h"
// Model
#import "NBNumberFormat.h"
#import "NBPhoneMetaData.h"
#import "NBPhoneNumber.h"
#import "NBPhoneNumberDesc.h"

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>libPhoneNumberwatchOS</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,33 @@
//
// libPhoneNumber-watchOS.h
// libPhoneNumber-watchOS
//
// Created by Jeff Kelley on 11/16/16.
// Copyright © 2016 ohtalk.me. All rights reserved.
//
#import <WatchKit/WatchKit.h>
//! Project version number for libPhoneNumber-watchOS.
FOUNDATION_EXPORT double libPhoneNumber_watchOSVersionNumber;
//! Project version string for libPhoneNumber-watchOS.
FOUNDATION_EXPORT const unsigned char libPhoneNumber_watchOSVersionString[];
// In this header, you should import all the public headers of your framework
// using statements like #import <libPhoneNumber_watchOS/PublicHeader.h>
#import "NBPhoneNumberDefines.h"
// Features
#import "NBAsYouTypeFormatter.h"
#import "NBPhoneNumberUtil.h"
// Metadata
#import "NBMetadataCore.h"
// Model
#import "NBNumberFormat.h"
#import "NBPhoneMetaData.h"
#import "NBPhoneNumber.h"
#import "NBPhoneNumberDesc.h"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:libPhoneNumber.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0940"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8B1FEF721EB7BE7C00FBDE87"
BuildableName = "SwiftDemo.app"
BlueprintName = "SwiftDemo"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8B1FEF721EB7BE7C00FBDE87"
BuildableName = "SwiftDemo.app"
BlueprintName = "SwiftDemo"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8B1FEF721EB7BE7C00FBDE87"
BuildableName = "SwiftDemo.app"
BlueprintName = "SwiftDemo"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8B1FEF721EB7BE7C00FBDE87"
BuildableName = "SwiftDemo.app"
BlueprintName = "SwiftDemo"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0940"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "34ACBB841B7122AC0064B3BD"
BuildableName = "libPhoneNumberiOS.framework"
BlueprintName = "libPhoneNumberiOS"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14B7A2921DE9B65D0051AED7"
BuildableName = "libPhoneNumberiOSTests.xctest"
BlueprintName = "libPhoneNumberiOSTests"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "34ACBB841B7122AC0064B3BD"
BuildableName = "libPhoneNumberiOS.framework"
BlueprintName = "libPhoneNumberiOS"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "34ACBB841B7122AC0064B3BD"
BuildableName = "libPhoneNumberiOS.framework"
BlueprintName = "libPhoneNumberiOS"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "34ACBB841B7122AC0064B3BD"
BuildableName = "libPhoneNumberiOS.framework"
BlueprintName = "libPhoneNumberiOS"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0940"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14B7A2921DE9B65D0051AED7"
BuildableName = "libPhoneNumberiOSTests.xctest"
BlueprintName = "libPhoneNumberiOSTests"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14B7A2921DE9B65D0051AED7"
BuildableName = "libPhoneNumberiOSTests.xctest"
BlueprintName = "libPhoneNumberiOSTests"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14B7A2921DE9B65D0051AED7"
BuildableName = "libPhoneNumberiOSTests.xctest"
BlueprintName = "libPhoneNumberiOSTests"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14B7A2921DE9B65D0051AED7"
BuildableName = "libPhoneNumberiOSTests.xctest"
BlueprintName = "libPhoneNumberiOSTests"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "14B7A2921DE9B65D0051AED7"
BuildableName = "libPhoneNumberiOSTests.xctest"
BlueprintName = "libPhoneNumberiOSTests"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0940"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7C72507B1E0EBE7D00F916ED"
BuildableName = "libPhoneNumbermacOS.framework"
BlueprintName = "libPhoneNumbermacOS"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7C72507B1E0EBE7D00F916ED"
BuildableName = "libPhoneNumbermacOS.framework"
BlueprintName = "libPhoneNumbermacOS"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7C72507B1E0EBE7D00F916ED"
BuildableName = "libPhoneNumbermacOS.framework"
BlueprintName = "libPhoneNumbermacOS"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0940"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1F31D54C1DDD47B900257818"
BuildableName = "libPhoneNumbertvOS.framework"
BlueprintName = "libPhoneNumbertvOS"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1F31D54C1DDD47B900257818"
BuildableName = "libPhoneNumbertvOS.framework"
BlueprintName = "libPhoneNumbertvOS"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1F31D54C1DDD47B900257818"
BuildableName = "libPhoneNumbertvOS.framework"
BlueprintName = "libPhoneNumbertvOS"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0940"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1F31D5291DDD46B100257818"
BuildableName = "libPhoneNumberwatchOS.framework"
BlueprintName = "libPhoneNumberwatchOS"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1F31D5291DDD46B100257818"
BuildableName = "libPhoneNumberwatchOS.framework"
BlueprintName = "libPhoneNumberwatchOS"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1F31D5291DDD46B100257818"
BuildableName = "libPhoneNumberwatchOS.framework"
BlueprintName = "libPhoneNumberwatchOS"
ReferencedContainer = "container:libPhoneNumber.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,95 @@
#!/bin/sh
# GeneratePhoneNumberHeader.sh
# libPhoneNumber
#
# Created by Dave MacLachlan on 2/7/17.
# Copyright © 2017 Google Inc. All rights reserved.
# Takes the data sets in the PhoneNumberMetaData testing files and compresses them and then
# writes them into a header that we can pull into our source. The compression reduces them from 300k
# of data to 44k (per architecture). It would possibly be better to have this as a resource file
# that is read in from disk (because then we only pay for the size once), but that would
# dramatically change how this library is currently used by clients.
#
# The data set used is controlled by the value of the "TESTING" macro when the code is actually
# compiled.
set -eu
cd "${BASH_SOURCE%/*}" || exit
TEMPDIR=$(mktemp -d)
gzip -c "../libPhoneNumberTests/generatedJSON/PhoneNumberMetaDataForTesting.json" > "$TEMPDIR/PhoneNumberMetaDataForTesting.zip"
gzip -c "../libPhoneNumberTests/generatedJSON/PhoneNumberMetaData.json" > "$TEMPDIR/PhoneNumberMetaData.zip"
gzip -c "../libPhoneNumberTests/generatedJSON/ShortNumberMetaData.json" > "$TEMPDIR/ShortNumberMetaData.zip"
cat > "NBGeneratedPhoneNumberMetaData.h" <<'EOF'
/*****
* Data Generated from GeneratePhoneNumberHeader.sh
* Off of PhoneNumberMetaDataForTesting.json, PhoneNumberMetaData.json, and ShortNumberMetaData.json
*/
#include <zlib.h>
// z_const is not defined in some versions of zlib, so define it here
// in case it has not been defined.
#if defined(ZLIB_CONST) && !defined(z_const)
# define z_const const
#else
# define z_const
#endif
#if TESTING==1
z_const Bytef kPhoneNumberMetaData[] = {
EOF
cat "$TEMPDIR/PhoneNumberMetaDataForTesting.zip" | xxd -i >> "NBGeneratedPhoneNumberMetaData.h"
cat >> "NBGeneratedPhoneNumberMetaData.h" <<'EOF'
};
z_const size_t kPhoneNumberMetaDataCompressedLength = sizeof(kPhoneNumberMetaData);
EOF
LIB_SIZE=$(stat -f%z "../libPhoneNumberTests/generatedJSON/PhoneNumberMetaDataForTesting.json")
echo "z_const size_t kPhoneNumberMetaDataExpandedLength = $LIB_SIZE;" >> "NBGeneratedPhoneNumberMetaData.h"
cat >> "NBGeneratedPhoneNumberMetaData.h" <<'EOF'
#else // TESTING == 1
z_const Bytef kPhoneNumberMetaData[] = {
EOF
cat "$TEMPDIR/PhoneNumberMetaData.zip" | xxd -i >> "NBGeneratedPhoneNumberMetaData.h"
cat >> "NBGeneratedPhoneNumberMetaData.h" <<'EOF'
};
z_const size_t kPhoneNumberMetaDataCompressedLength = sizeof(kPhoneNumberMetaData);
EOF
LIB_SIZE=$(stat -f%z "../libPhoneNumberTests/generatedJSON/PhoneNumberMetaData.json")
echo "z_const size_t kPhoneNumberMetaDataExpandedLength = $LIB_SIZE;" >> "NBGeneratedPhoneNumberMetaData.h"
echo "#endif // TESTING" >> "NBGeneratedPhoneNumberMetaData.h"
# ShortNumberMetadata
cat >> "NBGeneratedPhoneNumberMetaData.h" <<'EOF'
#if SHORT_NUMBER_SUPPORT
z_const Bytef kShortNumberMetaData[] = {
EOF
cat "$TEMPDIR/ShortNumberMetaData.zip" | xxd -i >> "NBGeneratedPhoneNumberMetaData.h"
cat >> "NBGeneratedPhoneNumberMetaData.h" <<'EOF'
};
z_const size_t kShortNumberMetaDataCompressedLength = sizeof(kShortNumberMetaData);
EOF
LIB_SIZE=$(stat -f%z "../libPhoneNumberTests/generatedJSON/ShortNumberMetaData.json")
echo "z_const size_t kShortNumberMetaDataExpandedLength = $LIB_SIZE;" >> "NBGeneratedPhoneNumberMetaData.h"
echo "#endif // SHORT_NUMBER_SUPPORT" >> "NBGeneratedPhoneNumberMetaData.h"
rm "$TEMPDIR/PhoneNumberMetaDataForTesting.zip"
rm "$TEMPDIR/PhoneNumberMetaData.zip"
rm "$TEMPDIR/ShortNumberMetaData.zip"
rmdir "$TEMPDIR"

View File

@ -8,12 +8,11 @@
#import <Foundation/Foundation.h>
@class NBAsYouTypeFormatter;
@class NBMetadataHelper;
@interface NBAsYouTypeFormatter : NSObject
- (instancetype)initWithRegionCode:(NSString *)regionCode;
- (instancetype)initWithRegionCode:(NSString *)regionCode metadataHelper:(NBMetadataHelper *)helper;
- (instancetype)initWithRegionCode:(NSString *)regionCode bundle:(NSBundle *)bundle;
- (NSString *)inputString:(NSString *)string;
- (NSString *)inputStringAndRememberPosition:(NSString *)string;

View File

@ -51,7 +51,6 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
positionToRemember_;
@property(nonatomic, strong, readwrite) NSMutableArray *possibleFormats_;
@property(nonatomic, strong, readwrite) NBPhoneMetaData *currentMetaData_, *defaultMetaData_;
@property(nonatomic, strong) NBMetadataHelper *metadataHelper;
@end
@ -135,8 +134,7 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
* @private
*/
NSString *eligible_format =
@"^[-x-―−ー-- "
@"­ ().\\[\\]/~]*(\\$\\d[-x-―−ー-- "
@"^[-x-―−ー-- ­ ().\\[\\]/~]*(\\$\\d[-x-―−ー-- "
@"­ ().\\[\\]/~]*)+$";
self.ELIGIBLE_FORMAT_PATTERN_ =
[NSRegularExpression regularExpressionWithPattern:eligible_format options:0 error:&anError];
@ -265,19 +263,17 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
*/
- (instancetype)initWithRegionCode:(NSString *)regionCode {
return [self initWithRegionCode:regionCode metadataHelper:[[NBMetadataHelper alloc] init]];
return [self initWithRegionCode:regionCode bundle:[NSBundle mainBundle]];
}
- (instancetype)initWithRegionCode:(NSString *)regionCode
metadataHelper:(NBMetadataHelper *)helper {
- (instancetype)initWithRegionCode:(NSString *)regionCode bundle:(NSBundle *)bundle {
self = [self init];
if (self) {
/**
* @private
* @type {i18n.phonenumbers.PhoneNumberUtil}
*/
self.metadataHelper = helper;
self.phoneUtil_ = [[NBPhoneNumberUtil alloc] initWithMetadataHelper:helper];
self.phoneUtil_ = [NBPhoneNumberUtil sharedInstance];
self.defaultCountry_ = regionCode;
self.currentMetaData_ = [self getMetadataForRegion_:self.defaultCountry_];
/**
@ -299,7 +295,7 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
* @private
*/
- (NBPhoneMetaData *)getMetadataForRegion_:(NSString *)regionCode {
NBMetadataHelper *helper = self.metadataHelper;
NBMetadataHelper *helper = [[NBMetadataHelper alloc] init];
/** @type {number} */
NSNumber *countryCallingCode = [self.phoneUtil_ getCountryCodeForRegion:regionCode];
/** @type {string} */
@ -422,8 +418,8 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
for (NSUInteger i = 0; i < possibleFormatsLength; ++i) {
/** @type {i18n.phonenumbers.NumberFormat} */
NBNumberFormat *format = [self.possibleFormats_ nb_safeObjectAtIndex:i
class:[NBNumberFormat class]];
NBNumberFormat *format =
[self.possibleFormats_ nb_safeObjectAtIndex:i class:[NBNumberFormat class]];
if (format.leadingDigitsPatterns.count == 0) {
// Keep everything that isn't restricted by leading digits.
@ -520,9 +516,8 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
withTemplate:numberFormat];
// Replaces each digit with character DIGIT_PLACEHOLDER
template = [self.phoneUtil_ replaceStringByRegex:template
regex:@"9"
withTemplate:NBDigitPlaceHolder];
template =
[self.phoneUtil_ replaceStringByRegex:template regex:@"9" withTemplate:NBDigitPlaceHolder];
return template;
}
@ -651,8 +646,8 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
if (!nextChar || nextChar.length <= 0) {
return self.currentOutput_;
}
self.currentOutput_ = [self inputDigitWithOptionToRememberPosition_:nextChar
rememberPosition:YES];
self.currentOutput_ =
[self inputDigitWithOptionToRememberPosition_:nextChar rememberPosition:YES];
return self.currentOutput_;
}
@ -682,8 +677,8 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
self.ableToFormat_ = NO;
self.inputHasFormatting_ = YES;
} else {
nextChar = [self normalizeAndAccrueDigitsAndPlusSign_:nextChar
rememberPosition:rememberPosition];
nextChar =
[self normalizeAndAccrueDigitsAndPlusSign_:nextChar rememberPosition:rememberPosition];
}
if (!self.ableToFormat_) {
@ -775,6 +770,8 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
return [self attemptToChooseFormattingPattern_];
}
}
_isSuccessfulFormatting = NO;
}
/**
@ -810,12 +807,10 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
NSString *prefixBeforeNationalNumberStr = [self.prefixBeforeNationalNumber_ copy];
NSRange lastRange = [prefixBeforeNationalNumberStr rangeOfString:self.nationalPrefixExtracted_
options:NSBackwardsSearch];
if (lastRange.length > 0) {
/** @type {number} */
NSUInteger indexOfPreviousNdd = lastRange.location;
self.prefixBeforeNationalNumber_ = [[prefixBeforeNationalNumberStr
substringWithRange:NSMakeRange(0, indexOfPreviousNdd)] mutableCopy];
}
/** @type {number} */
NSUInteger indexOfPreviousNdd = lastRange.location;
self.prefixBeforeNationalNumber_ = [[prefixBeforeNationalNumberStr
substringWithRange:NSMakeRange(0, indexOfPreviousNdd)] mutableCopy];
}
return self.nationalPrefixExtracted_ != [self removeNationalPrefixFromNationalNumber_];
@ -856,8 +851,8 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
NSString *pattern = numberFormat.pattern;
/** @type {RegExp} */
NSString *patternRegExp = [NSString stringWithFormat:@"^(?:%@)$", pattern];
BOOL isPatternRegExp = [[self.phoneUtil_ matchesByRegex:nationalNumber
regex:patternRegExp] count] > 0;
BOOL isPatternRegExp =
[[self.phoneUtil_ matchesByRegex:nationalNumber regex:patternRegExp] count] > 0;
if (isPatternRegExp) {
if (numberFormat.nationalPrefixFormattingRule.length > 0) {
NSArray *matches = [self.NATIONAL_PREFIX_SEPARATORS_PATTERN_
@ -1031,8 +1026,8 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
NSString *nationalPrefixForParsing =
[NSString stringWithFormat:@"^(?:%@)", self.currentMetaData_.nationalPrefixForParsing];
/** @type {Array.<string>} */
NSArray *m = [self.phoneUtil_ matchedStringByRegex:nationalNumber
regex:nationalPrefixForParsing];
NSArray *m =
[self.phoneUtil_ matchedStringByRegex:nationalNumber regex:nationalPrefixForParsing];
NSString *firstString = [m nb_safeStringAtIndex:0];
if (m != nil && firstString != nil && firstString.length > 0) {
// When the national prefix is detected, we use international formatting
@ -1116,7 +1111,7 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
NSString *newRegionCode = [self.phoneUtil_ getRegionCodeForCountryCode:countryCode];
if ([NB_REGION_CODE_FOR_NON_GEO_ENTITY isEqualToString:newRegionCode]) {
NBMetadataHelper *helper = self.metadataHelper;
NBMetadataHelper *helper = [[NBMetadataHelper alloc] init];
self.currentMetaData_ = [helper getMetadataForNonGeographicalRegion:countryCode];
} else if (newRegionCode != self.defaultCountry_) {
self.currentMetaData_ = [self getMetadataForRegion_:newRegionCode];
@ -1180,8 +1175,8 @@ static const NSUInteger NBMinLeadingDigitsLength = 3;
if ([self.phoneUtil_ stringPositionByRegex:subedString regex:NBDigitPlaceHolder] >= 0) {
/** @type {number} */
int digitPatternStart = [self.phoneUtil_ stringPositionByRegex:formattingTemplate
regex:NBDigitPlaceHolder];
int digitPatternStart =
[self.phoneUtil_ stringPositionByRegex:formattingTemplate regex:NBDigitPlaceHolder];
/** @type {string} */
NSRange tempRange = [formattingTemplate rangeOfString:NBDigitPlaceHolder];

File diff suppressed because it is too large Load Diff

View File

@ -15,15 +15,27 @@
+ (BOOL)hasValue:(NSString *)string;
- (instancetype)init;
+ (NSDictionary *)CCode2CNMap;
- (NSArray *)regionCodeFromCountryCode:(NSNumber *)countryCodeNumber;
- (NSString *)countryCodeFromRegionCode:(NSString *)regionCode;
- (NSArray *)getAllMetadata;
- (NBPhoneMetaData *)getMetadataForNonGeographicalRegion:(NSNumber *)countryCallingCode;
- (NBPhoneMetaData *)getMetadataForRegion:(NSString *)regionCode;
- (NSDictionary *)countryCodeToCountryNumberDictionary;
- (NSArray *)getAllMetadata;
+ (NSArray *)regionCodeFromCountryCode:(NSNumber *)countryCodeNumber;
+ (NSString *)countryCodeFromRegionCode:(NSString *)regionCode;
#if SHORT_NUMBER_SUPPORT
/**
* Returns the short number metadata for the given region code or {@code nil} if the region
* code is invalid or unknown.
*
* @param regionCode regionCode
* @return {i18n.phonenumbers.PhoneMetadata}
*/
- (NBPhoneMetaData *)shortNumberMetadataForRegion:(NSString *)regionCode;
#endif // SHORT_NUMBER_SUPPORT
@end

View File

@ -7,13 +7,19 @@
//
#import "NBMetadataHelper.h"
#import "NBGeneratedPhoneNumberMetaData.h"
#import "NBPhoneMetaData.h"
@interface NBMetadataHelper ()
// Cached metadata
@property(nonatomic, strong) NSCache<NSString *, NBPhoneMetaData *> *metadataCache;
@property(nonatomic, strong) NSCache<NSString *, id> *metadataMapCache;
@property (nonatomic, strong) NSCache<NSString *, NBPhoneMetaData *> *metadataCache;
#if SHORT_NUMBER_SUPPORT
@property (nonatomic, strong) NSCache<NSString *, NBPhoneMetaData *> *shortNumberMetadataCache;
#endif //SHORT_NUMBER_SUPPORT
@end
@ -29,22 +35,16 @@ static NSString *StringByTrimming(NSString *aString) {
return [aString stringByTrimmingCharactersInSet:whitespaceCharSet];
}
@implementation NBMetadataHelper {
@private
NSDictionary *_phoneNumberDataDictionary;
NSDictionary *_countryCodeToCountryNumberDictionary;
}
@implementation NBMetadataHelper
- (instancetype)init {
self = [super init];
if (self != nil) {
_metadataCache = [[NSCache alloc] init];
_metadataMapCache = [[NSCache alloc] init];
_phoneNumberDataDictionary = [[self class] phoneNumberDataMap];
[self countryCodeToCountryNumberDictionary];
#if SHORT_NUMBER_SUPPORT
_shortNumberMetadataCache = [[NSCache alloc] init];
#endif //SHORT_NUMBER_SUPPORT
}
return self;
}
@ -55,42 +55,35 @@ static NSString *StringByTrimming(NSString *aString) {
Ref. site (countrycode.org)
*/
+ (NSDictionary *)phoneNumberDataMap {
static NSDictionary *result;
static NSDictionary *phoneNumberDataDictionary;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
@autoreleasepool {
NSString *path = [[NSBundle bundleForClass:NBMetadataHelper.class] pathForResource:@"NBPhoneNumberMetaData" ofType:@"plist"];
NSData *fileContent = [NSData dataWithContentsOfFile:path];
if (fileContent != nil) {
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:fileContent error:NULL];
unarchiver.requiresSecureCoding = YES;
NSSet *allowedClasses = [NSSet setWithArray:@[NSArray.class, NSDictionary.class, NSNull.class, NSString.class, NSNumber.class]];
result = (NSDictionary *)[unarchiver decodeObjectOfClasses:allowedClasses forKey:NSKeyedArchiveRootObjectKey];
}
NSAssert(result != nil, @"NBPhoneNumberMetaData.plist missing or corrupt");
}
phoneNumberDataDictionary =
[self jsonObjectFromZippedDataWithBytes:kPhoneNumberMetaData
compressedLength:kPhoneNumberMetaDataCompressedLength
expandedLength:kPhoneNumberMetaDataExpandedLength];
});
return result;
return phoneNumberDataDictionary;
}
- (NSDictionary *)countryCodeToCountryNumberDictionary {
if (_countryCodeToCountryNumberDictionary == nil) {
NSDictionary *countryCodeToRegionCodeMap = [self countryCodeToRegionCodeDictionary];
NSMutableDictionary *map = [[NSMutableDictionary alloc] init];
+ (NSDictionary *)CCode2CNMap {
static NSMutableDictionary *mapCCode2CN;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSDictionary *countryCodeToRegionCodeMap = [self CN2CCodeMap];
mapCCode2CN = [[NSMutableDictionary alloc] init];
for (NSString *countryCode in countryCodeToRegionCodeMap) {
NSArray *regionCodes = countryCodeToRegionCodeMap[countryCode];
for (NSString *regionCode in regionCodes) {
map[regionCode] = countryCode;
mapCCode2CN[regionCode] = countryCode;
}
}
_countryCodeToCountryNumberDictionary = [map copy];
}
return _countryCodeToCountryNumberDictionary;
});
return mapCCode2CN;
}
- (NSDictionary *)countryCodeToRegionCodeDictionary {
return _phoneNumberDataDictionary[@"countryCodeToRegionCodeMap"];
+ (NSDictionary *)CN2CCodeMap {
return [self phoneNumberDataMap][@"countryCodeToRegionCodeMap"];
}
- (NSArray *)getAllMetadata {
@ -98,18 +91,18 @@ static NSString *StringByTrimming(NSString *aString) {
NSMutableArray *resultMetadata = [[NSMutableArray alloc] initWithCapacity:countryCodes.count];
for (NSString *countryCode in countryCodes) {
id countryDictionaryInstance = [NSDictionary dictionaryWithObject:countryCode
forKey:NSLocaleCountryCode];
id countryDictionaryInstance =
[NSDictionary dictionaryWithObject:countryCode forKey:NSLocaleCountryCode];
NSString *identifier = [NSLocale localeIdentifierFromComponents:countryDictionaryInstance];
NSString *country = [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier
value:identifier];
NSString *country =
[[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:identifier];
NSMutableDictionary *countryMeta = [[NSMutableDictionary alloc] init];
if (country) {
[countryMeta setObject:country forKey:@"name"];
} else {
NSString *systemCountry = [[NSLocale systemLocale] displayNameForKey:NSLocaleIdentifier
value:identifier];
NSString *systemCountry =
[[NSLocale systemLocale] displayNameForKey:NSLocaleIdentifier value:identifier];
if (systemCountry) {
[countryMeta setObject:systemCountry forKey:@"name"];
}
@ -130,8 +123,8 @@ static NSString *StringByTrimming(NSString *aString) {
return resultMetadata;
}
- (NSArray *)regionCodeFromCountryCode:(NSNumber *)countryCodeNumber {
NSArray *res = [self countryCodeToRegionCodeDictionary][[countryCodeNumber stringValue]];
+ (NSArray *)regionCodeFromCountryCode:(NSNumber *)countryCodeNumber {
NSArray *res = [self CN2CCodeMap][[countryCodeNumber stringValue]];
if ([res isKindOfClass:[NSArray class]] && [res count] > 0) {
return res;
}
@ -139,8 +132,8 @@ static NSString *StringByTrimming(NSString *aString) {
return nil;
}
- (NSString *)countryCodeFromRegionCode:(NSString *)regionCode {
return [self countryCodeToCountryNumberDictionary][regionCode];
+ (NSString *)countryCodeFromRegionCode:(NSString *)regionCode {
return [self CCode2CNMap][regionCode];
}
/**
@ -163,7 +156,7 @@ static NSString *StringByTrimming(NSString *aString) {
return cachedMetadata;
}
NSDictionary *dict = _phoneNumberDataDictionary[@"countryToMetadata"];
NSDictionary *dict = [[self class] phoneNumberDataMap][@"countryToMetadata"];
NSArray *entry = dict[regionCode];
if (entry) {
NBPhoneMetaData *metadata = [[NBPhoneMetaData alloc] initWithEntry:entry];
@ -189,4 +182,86 @@ static NSString *StringByTrimming(NSString *aString) {
return string.length != 0;
}
#if SHORT_NUMBER_SUPPORT
+ (NSDictionary *)shortNumberDataMap {
static NSDictionary *shortNumberDataDictionary;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shortNumberDataDictionary =
[self jsonObjectFromZippedDataWithBytes:kShortNumberMetaData
compressedLength:kShortNumberMetaDataCompressedLength
expandedLength:kShortNumberMetaDataExpandedLength];
});
return shortNumberDataDictionary;
}
- (NBPhoneMetaData *)shortNumberMetadataForRegion:(NSString *)regionCode
{
regionCode = StringByTrimming(regionCode);
if (regionCode.length == 0) {
return nil;
}
regionCode = [regionCode uppercaseString];
NBPhoneMetaData *cachedMetadata = [_shortNumberMetadataCache objectForKey:regionCode];
if (cachedMetadata != nil) {
return cachedMetadata;
}
NSDictionary *dict = [[self class] shortNumberDataMap][@"countryToMetadata"];
NSArray *entry = dict[regionCode];
if (entry) {
NBPhoneMetaData *metadata = [[NBPhoneMetaData alloc] initWithEntry:entry];
[_shortNumberMetadataCache setObject:metadata forKey:regionCode];
return metadata;
}
return nil;
}
#endif // SHORT_NUMBER_SUPPORT
/**
* Expand gzipped data into a JSON object.
* @param bytes Array<Bytef> of zipped data.
* @param compressedLength Length of the compressed bytes.
* @param expandedLength Length of the expanded bytes.
* @return JSON dictionary.
*/
+ (NSDictionary *)jsonObjectFromZippedDataWithBytes:(z_const Bytef [])bytes
compressedLength:(NSUInteger)compressedLength
expandedLength:(NSUInteger)expandedLength {
// Data is a gzipped JSON file that is embedded in the binary.
// See GeneratePhoneNumberHeader.sh and PhoneNumberMetaData.h for details.
NSMutableData* gunzippedData = [NSMutableData dataWithLength:expandedLength];
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 = bytes;
zStream.avail_in = (uint)compressedLength;
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;
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:gunzippedData
options:0
error:&error];
NSAssert(error == nil, @"Unable to convert JSON - %@", error);
return jsonObject;
}
@end

View File

@ -39,10 +39,14 @@
/* 23 */ @property(nonatomic, strong) NSString *leadingDigits;
/* 26 */ @property(nonatomic, assign) BOOL leadingZeroPossible;
/* 29 */ @property(nonatomic, strong) NBPhoneNumberDesc *shortCode;
/* 30 */ @property(nonatomic, strong) NBPhoneNumberDesc *standardRate;
/* 31 */ @property(nonatomic, strong) NBPhoneNumberDesc *carrierSpecific;
/* 33 */ @property(nonatomic, strong) NBPhoneNumberDesc *smsServices;
#if SHORT_NUMBER_SUPPORT
/* 29 */ @property (nonatomic, strong) NBPhoneNumberDesc *shortCode;
/* 30 */ @property (nonatomic, strong) NBPhoneNumberDesc *standardRate;
/* 31 */ @property (nonatomic, strong) NBPhoneNumberDesc *carrierSpecific;
/* 33 */ @property (nonatomic, strong) NBPhoneNumberDesc *smsServices;
#endif // SHORT_NUMBER_SUPPORT
- (instancetype)initWithEntry:(NSArray *)entry;
@end

View File

@ -59,10 +59,12 @@
_leadingDigits = [entry nb_safeStringAtIndex:23];
_leadingZeroPossible = [[entry nb_safeNumberAtIndex:26] boolValue];
#if SHORT_NUMBER_SUPPORT
_shortCode = [[NBPhoneNumberDesc alloc] initWithEntry:[entry nb_safeArrayAtIndex:29]];
_standardRate = [[NBPhoneNumberDesc alloc] initWithEntry:[entry nb_safeArrayAtIndex:30]];
_carrierSpecific = [[NBPhoneNumberDesc alloc] initWithEntry:[entry nb_safeArrayAtIndex:31]];
_smsServices = [[NBPhoneNumberDesc alloc] initWithEntry:[entry nb_safeArrayAtIndex:33]];
#endif // SHORT_NUMBER_SUPPORT
}
return self;

View File

@ -7,7 +7,7 @@
#import <Foundation/Foundation.h>
#import "NBPhoneNumberDefines.h"
@interface NBPhoneNumber : NSObject <NSCopying, NSCoding>
@interface NBPhoneNumber : NSObject<NSCopying, NSCoding>
// from phonemetadata.pb.js
/* 1 */ @property(nonatomic, strong, readwrite) NSNumber *countryCode;

View File

@ -98,8 +98,8 @@
}
- (NSString *)description {
return [NSString
stringWithFormat:@" - countryCode[%@], nationalNumber[%@], extension[%@], "
return [NSString stringWithFormat:
@" - countryCode[%@], nationalNumber[%@], extension[%@], "
@"italianLeadingZero[%@], numberOfLeadingZeros[%@], rawInput[%@] "
@"countryCodeSource[%@] preferredDomesticCarrierCode[%@]",
self.countryCode, self.nationalNumber, self.extension,

View File

@ -24,8 +24,8 @@
}
- (NSString *)description {
return [NSString
stringWithFormat:@"nationalNumberPattern[%@] possibleNumberPattern[%@] possibleLength[%@] "
return [NSString stringWithFormat:
@"nationalNumberPattern[%@] possibleNumberPattern[%@] possibleLength[%@] "
@"possibleLengthLocalOnly[%@] exampleNumber[%@]",
self.nationalNumberPattern, self.possibleNumberPattern, self.possibleLength,
self.possibleLengthLocalOnly, self.exampleNumber];

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,198 @@
//
// NBPhoneNumberUtil+ShortNumber.h
// libPhoneNumberiOS
//
// Created by Paween Itthipalkul on 11/29/17.
// Copyright © 2017 Google LLC. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "NBPhoneNumberUtil.h"
@class NBPhoneNumber;
NS_ASSUME_NONNULL_BEGIN
#if SHORT_NUMBER_SUPPORT
typedef NS_ENUM(NSUInteger, NBEShortNumberCost) {
NBEShortNumberCostUnknown = 0,
NBEShortNumberCostTollFree = 1,
NBEShortNumberCostStandardRate = 2,
NBEShortNumberCostPremiumRate = 3,
};
@interface NBPhoneNumberUtil (ShortNumber)
// Short number related methods
/**
* Check whether a short number is a possible number when dialed from the given region. This
* provides a more lenient check than {@link #isValidShortNumberForRegion}.
*
* @param phoneNumber the short number to check
* @param regionDialingFrom the region from which the number is dialed
* @return whether the number is a possible short number
*/
- (BOOL)isPossibleShortNumber:(NBPhoneNumber *)phoneNumber forRegion:(NSString *)regionDialingFrom;
/**
* Check whether a short number is a possible number. If a country calling code is shared by
* multiple regions, this returns true if it's possible in any of them. This provides a more
* lenient check than {@link #isValidShortNumber}. See {@link
* #isPossibleShortNumberForRegion(PhoneNumber, String)} for details.
*
* @param phoneNumber the short number to check
* @return whether the number is a possible short number
*/
- (BOOL)isPossibleShortNumber:(NBPhoneNumber *)phoneNumber;
/**
* 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 phoneNumber 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
*/
- (BOOL)isValidShortNumber:(NBPhoneNumber *)phoneNumber forRegion:(NSString *)regionDialingFrom;
/**
* Tests whether a short number matches a valid pattern. If a country calling code is shared by
* multiple regions, this returns true if it's valid in any of them. Note that this doesn't verify
* the number is actually in use, which is impossible to tell by just looking at the number
* itself. See {@link #isValidShortNumberForRegion(PhoneNumber, String)} for details.
*
* @param phoneNumber the short number for which we want to test the validity
* @return whether the short number matches a valid pattern
*/
- (BOOL)isValidShortNumber:(NBPhoneNumber *)phoneNumber;
/**
* Gets the expected cost category of a short number when dialed from a region (however, nothing
* is implied about its validity). If it is important that the number is valid, then its validity
* must first be checked using {@link #isValidShortNumberForRegion}. Note that emergency numbers
* are always considered toll-free. Example usage:
* <pre>{@code
* // The region for which the number was parsed and the region we subsequently check against
* // need not be the same. Here we parse the number in the US and check it for Canada.
* PhoneNumber number = phoneUtil.parse("110", "US");
* ...
* String regionCode = "CA";
* ShortNumberInfo shortInfo = ShortNumberInfo.getInstance();
* if (shortInfo.isValidShortNumberForRegion(shortNumber, regionCode)) {
* ShortNumberCost cost = shortInfo.getExpectedCostForRegion(number, regionCode);
* // Do something with the cost information here.
* }}</pre>
*
* @param phoneNumber the short number for which we want to know the expected cost category
* @param regionDialingFrom the region from which the number is dialed
* @return the expected cost category for that region of the short number. Returns UNKNOWN_COST if
* the number does not match a cost category. Note that an invalid number may match any cost
* category.
*/
- (NBEShortNumberCost)expectedCostOfPhoneNumber:(NBPhoneNumber *)phoneNumber
forRegion:(NSString *)regionDialingFrom;
/**
* Gets the expected cost category of a short number (however, nothing is implied about its
* validity). If the country calling code is unique to a region, this method behaves exactly the
* same as {@link #getExpectedCostForRegion(PhoneNumber, String)}. However, if the country
* calling code is shared by multiple regions, then it returns the highest cost in the sequence
* PREMIUM_RATE, UNKNOWN_COST, STANDARD_RATE, TOLL_FREE. The reason for the position of
* UNKNOWN_COST in this order is that if a number is UNKNOWN_COST in one region but STANDARD_RATE
* or TOLL_FREE in another, its expected cost cannot be estimated as one of the latter since it
* might be a PREMIUM_RATE number.
* <p>
* For example, if a number is STANDARD_RATE in the US, but TOLL_FREE in Canada, the expected
* cost returned by this method will be STANDARD_RATE, since the NANPA countries share the same
* country calling code.
* <p>
* Note: If the region from which the number is dialed is known, it is highly preferable to call
* {@link #getExpectedCostForRegion(PhoneNumber, String)} instead.
*
* @param phoneNumber the short number for which we want to know the expected cost category
* @return the highest expected cost category of the short number in the region(s) with the given
* country calling code
*/
- (NBEShortNumberCost)expectedCostOfPhoneNumber:(NBPhoneNumber *)phoneNumber;
/**
* Given a valid short number, determines whether it is carrier-specific (however, nothing is
* implied about its validity). Carrier-specific numbers may connect to a different end-point, or
* not connect at all, depending on the user's carrier. If it is important that the number is
* valid, then its validity must first be checked using {@link #isValidShortNumber} or
* {@link #isValidShortNumberForRegion}.
*
* @param phoneNumber the valid short number to check
* @return whether the short number is carrier-specific, assuming the input was a valid short
* number
*/
- (BOOL)isPhoneNumberCarrierSpecific:(NBPhoneNumber *)phoneNumber;
/**
* Given a valid short number, determines whether it is carrier-specific when dialed from the
* given region (however, nothing is implied about its validity). Carrier-specific numbers may
* connect to a different end-point, or not connect at all, depending on the user's carrier. If
* it is important that the number is valid, then its validity must first be checked using
* {@link #isValidShortNumber} or {@link #isValidShortNumberForRegion}. Returns false if the
* number doesn't match the region provided.
*
* @param phoneNumber the valid short number to check
* @param regionDialingFrom the region from which the number is dialed
* @return whether the short number is carrier-specific in the provided region, assuming the
* input was a valid short number
*/
- (BOOL)isPhoneNumberCarrierSpecific:(NBPhoneNumber *)phoneNumber forRegion:(NSString *)regionCode;
/**
* Given a valid short number, determines whether it is an SMS service (however, nothing is
* implied about its validity). An SMS service is where the primary or only intended usage is to
* receive and/or send text messages (SMSs). This includes MMS as MMS numbers downgrade to SMS if
* the other party isn't MMS-capable. If it is important that the number is valid, then its
* validity must first be checked using {@link #isValidShortNumber} or {@link
* #isValidShortNumberForRegion}. Returns false if the number doesn't match the region provided.
*
* @param phoneNumber the valid short number to check
* @param regionDialingFrom the region from which the number is dialed
* @return whether the short number is an SMS service in the provided region, assuming the input
* was a valid short number
*/
- (BOOL)isPhoneNumberSMSService:(NBPhoneNumber *)phoneNumber forRegion:(NSString *)regionCode;
/**
* Returns true if the given number, exactly as dialed, might be used to connect to an emergency
* service in the given region.
* <p>
* This method accepts a string, rather than a PhoneNumber, because it needs to distinguish
* cases such as "+1 911" and "911", where the former may not connect to an emergency service in
* all cases but the latter would. This method takes into account cases where the number might
* contain formatting, or might have additional digits appended (when it is okay to do that in
* the specified region).
*
* @param number the phone number to test
* @param regionCode the region where the phone number is being dialed
* @return whether the number might be used to connect to an emergency service in the given region
*/
- (BOOL)connectsToEmergencyNumberFromString:(NSString *)number forRegion:(NSString *)regionCode;
/**
* Returns true if the given number exactly matches an emergency service number in the given
* region.
* <p>
* This method takes into account cases where the number might contain formatting, but doesn't
* allow additional digits to be appended. Note that {@code isEmergencyNumber(number, region)}
* implies {@code connectsToEmergencyNumber(number, region)}.
*
* @param number the phone number to test
* @param regionCode the region where the phone number is being dialed
* @return whether the number exactly matches an emergency services number in the given region
*/
- (BOOL)isEmergencyNumber:(NSString *)number forRegion:(NSString *)regionCode;
@end
#endif // SHORT_NUMBER_SUPPORT
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,326 @@
//
// NBPhoneNumberUtil+ShortNumber.m
// libPhoneNumberiOS
//
// Created by Paween Itthipalkul on 11/29/17.
// Copyright © 2017 Google LLC. All rights reserved.
//
#import "NBPhoneNumberUtil+ShortNumber.h"
#import <Foundation/Foundation.h>
#import "NBMetadataHelper.h"
#import "NBPhoneMetaData.h"
#import "NBPhoneNumber.h"
#import "NBPhoneNumberDesc.h"
#import "NBRegExMatcher.h"
#import "NBRegularExpressionCache.h"
#if SHORT_NUMBER_SUPPORT
static NSString * const PLUS_CHARS_PATTERN = @"[+\uFF0B]+";
@interface NBPhoneNumberUtil()
@property(nonatomic, strong, readonly) NBMetadataHelper *helper;
@property(nonatomic, strong, readonly) NBRegExMatcher *matcher;
@property (nonatomic) NSDictionary<NSNumber *, NSArray<NSString *> *> *countryToRegionCodeMap;
@end
@implementation NBPhoneNumberUtil (ShortNumber)
- (BOOL)isPossibleShortNumber:(NBPhoneNumber *)phoneNumber forRegion:(NSString *)regionDialingFrom {
if (![self doesPhoneNumber:phoneNumber matchesRegion:regionDialingFrom]) {
return NO;
}
NBPhoneMetaData *metadata = [self.helper shortNumberMetadataForRegion:regionDialingFrom];
if (metadata == nil) {
return NO;
}
NSUInteger length = [[self getNationalSignificantNumber:phoneNumber] length];
return [metadata.generalDesc.possibleLength containsObject:@(length)];
}
- (BOOL)isPossibleShortNumber:(NBPhoneNumber *)phoneNumber {
NSArray<NSString *> *regionCodes = [self getRegionCodesForCountryCode:phoneNumber.countryCode];
NSUInteger shortNumberLength = [[self getNationalSignificantNumber:phoneNumber] length];
for (NSString *region in regionCodes) {
NBPhoneMetaData *metadata = [self.helper shortNumberMetadataForRegion:region];
if (metadata == nil) {
continue;
}
if ([metadata.generalDesc.possibleLength containsObject:@(shortNumberLength)]) {
return YES;
}
}
return NO;
}
- (BOOL)isValidShortNumber:(NBPhoneNumber *)phoneNumber
forRegion:(NSString *)regionDialingFrom {
if (![self doesPhoneNumber:phoneNumber matchesRegion:regionDialingFrom]) {
return NO;
}
NBPhoneMetaData *metadata = [self.helper shortNumberMetadataForRegion:regionDialingFrom];
if (metadata == nil) {
return NO;
}
NSString *shortNumber = [self getNationalSignificantNumber:phoneNumber];
NBPhoneNumberDesc *generalDesc = metadata.generalDesc;
if (![self matchesPossibleNumber:shortNumber andNationalNumber:generalDesc]) {
return NO;
}
NBPhoneNumberDesc *shortNumberDesc = metadata.shortCode;
return [self matchesPossibleNumber:shortNumber andNationalNumber:shortNumberDesc];
}
- (BOOL)isValidShortNumber:(NBPhoneNumber *)phoneNumber {
NSArray<NSString *> *regionCodes = [self getRegionCodesForCountryCode:phoneNumber.countryCode];
NSString *regionCode = [self regionCodeForShortNumber:phoneNumber fromRegionList:regionCodes];
if (regionCodes.count > 1 && regionCode != nil) {
// If a matching region had been found for the phone number from among two or more regions,
// then we have already implicitly verified its validity for that region.
return YES;
}
return [self isValidShortNumber:phoneNumber forRegion:regionCode];
}
- (NBEShortNumberCost)expectedCostOfPhoneNumber:(NBPhoneNumber *)phoneNumber
forRegion:(NSString *)regionDialingFrom {
if (![self doesRegionDialingFrom:regionDialingFrom matchesPhoneNumber:phoneNumber]) {
return NBEShortNumberCostUnknown;
}
NBPhoneMetaData *metadata = [self.helper shortNumberMetadataForRegion:regionDialingFrom];
if (metadata == nil) {
return NBEShortNumberCostUnknown;
}
NSString *shortNumber = [self getNationalSignificantNumber:phoneNumber];
// The possible lengths are not present for a particular sub-type if they match the general
// description; for this reason, we check the possible lengths against the general description
// first to allow an early exit if possible.
if (![metadata.generalDesc.possibleLength containsObject:@(shortNumber.length)]) {
return NBEShortNumberCostUnknown;
}
// The cost categories are tested in order of decreasing expense, since if for some reason the
// patterns overlap the most expensive matching cost category should be returned.
if ([self matchesPossibleNumber:shortNumber andNationalNumber:metadata.premiumRate]) {
return NBEShortNumberCostPremiumRate;
} else if ([self matchesPossibleNumber:shortNumber andNationalNumber:metadata.standardRate]) {
return NBEShortNumberCostStandardRate;
} else if ([self matchesPossibleNumber:shortNumber andNationalNumber:metadata.tollFree]) {
return NBEShortNumberCostTollFree;
}
if ([self isEmergencyNumber:shortNumber forRegion:regionDialingFrom]) {
// Emergency numbers are implicitly toll-free.
return NBEShortNumberCostTollFree;
}
return NBEShortNumberCostUnknown;
}
- (NBEShortNumberCost)expectedCostOfPhoneNumber:(NBPhoneNumber *)phoneNumber {
NSArray<NSString *> *regionCodes = [self getRegionCodesForCountryCode:phoneNumber.countryCode];
if (regionCodes.count == 0) {
return NBEShortNumberCostUnknown;
}
if (regionCodes.count == 1) {
return [self expectedCostOfPhoneNumber:phoneNumber forRegion:regionCodes[0]];
}
NBEShortNumberCost cost = NBEShortNumberCostTollFree;
for (NSString *regionCode in regionCodes) {
NBEShortNumberCost costForRegion = [self expectedCostOfPhoneNumber:phoneNumber
forRegion:regionCode];
switch (costForRegion) {
case NBEShortNumberCostPremiumRate:
return NBEShortNumberCostPremiumRate;
case NBEShortNumberCostUnknown:
cost = NBEShortNumberCostUnknown;
break;
case NBEShortNumberCostStandardRate:
if (cost != NBEShortNumberCostUnknown) {
cost = NBEShortNumberCostStandardRate;
}
break;
case NBEShortNumberCostTollFree:
// Do nothing.
break;
}
}
return cost;
}
- (BOOL)isPhoneNumberCarrierSpecific:(NBPhoneNumber *)phoneNumber {
NSArray<NSString *> *regionCodes = [self getRegionCodesForCountryCode:phoneNumber.countryCode];
NSString *regionCode = [self regionCodeForShortNumber:phoneNumber fromRegionList:regionCodes];
NSString *nationalNumber = [self getNationalSignificantNumber:phoneNumber];
NBPhoneMetaData *metadata = [self.helper shortNumberMetadataForRegion:regionCode];
return (metadata != nil &&
([self matchesPossibleNumber:nationalNumber andNationalNumber:metadata.carrierSpecific]));
}
- (BOOL)isPhoneNumberCarrierSpecific:(NBPhoneNumber *)phoneNumber forRegion:(NSString *)regionCode {
if (![self doesRegionDialingFrom:regionCode matchesPhoneNumber:phoneNumber]) {
return NO;
}
NSString *nationalNumber = [self getNationalSignificantNumber:phoneNumber];
NBPhoneMetaData *metadata = [self.helper shortNumberMetadataForRegion:regionCode];
return (metadata != nil
&& ([self matchesPossibleNumber:nationalNumber andNationalNumber:metadata.carrierSpecific]));
}
- (BOOL)isPhoneNumberSMSService:(NBPhoneNumber *)phoneNumber forRegion:(NSString *)regionCode {
if (![self doesRegionDialingFrom:regionCode matchesPhoneNumber:phoneNumber]) {
return NO;
}
NSString *nationalNumber = [self getNationalSignificantNumber:phoneNumber];
NBPhoneMetaData *metadata = [self.helper shortNumberMetadataForRegion:regionCode];
return (metadata != nil
&& ([self matchesPossibleNumber:nationalNumber andNationalNumber:metadata.smsServices]));
}
- (BOOL)connectsToEmergencyNumberFromString:(NSString *)number forRegion:(NSString *)regionCode {
return [self matchesEmergencyNumberHelper:number regionCode:regionCode allowsPrefixMatch:YES];
}
- (BOOL)isEmergencyNumber:(NSString *)number forRegion:(NSString *)regionCode {
return [self matchesEmergencyNumberHelper:number regionCode:regionCode allowsPrefixMatch:NO];
}
// MARK: - Private
// In these countries, if extra digits are added to an emergency number, it no longer connects
// to the emergency service.
+ (NSSet<NSString *> *)regionsWhereEmergencyNumbersMustBeExact {
static NSSet<NSString *> *regions;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
regions = [NSSet setWithObjects:@"BR", @"CL", @"NI", nil];
});
return regions;
}
/**
* Helper method to check that the country calling code of the number matches the region it's
* being dialed from.
*/
- (BOOL)doesPhoneNumber:(NBPhoneNumber *)phoneNumber matchesRegion:(NSString *)regionCode {
NSArray<NSString *> *regionCodes = [self getRegionCodesForCountryCode:phoneNumber.countryCode];
return [regionCodes containsObject:regionCode];
}
/**
* Gets the national significant number of the a phone number. Note a national significant number
* doesn't contain a national prefix or any formatting.
* <p>
* This is a temporary duplicate of the {@code getNationalSignificantNumber} method from
* {@code PhoneNumberUtil}. Ultimately a canonical static version should exist in a separate
* utility class (to prevent {@code ShortNumberInfo} needing to depend on PhoneNumberUtil).
*
* @param number the phone number for which the national significant number is needed
* @return the national significant number of the PhoneNumber object passed in
*/
+ (NSString *)nationalSignificantNumberFromPhoneNumber:(NBPhoneNumber *)phoneNumber {
// If leading zero(s) have been set, we prefix this now. Note this is not a national prefix.
NSMutableString *nationalNumber = [[NSMutableString alloc] init];
if (phoneNumber.italianLeadingZero) {
[nationalNumber appendFormat:@"%*d", [phoneNumber.numberOfLeadingZeros intValue], 0];
}
[nationalNumber appendString:[phoneNumber.nationalNumber stringValue]];
return [nationalNumber copy];
}
- (BOOL)matchesPossibleNumber:(NSString *)number andNationalNumber:(NBPhoneNumberDesc *)numberDesc {
if (numberDesc.possibleLength.count > 0
&& ![numberDesc.possibleLength containsObject:@(number.length)]) {
return NO;
}
return [self.matcher matchNationalNumber:number phoneNumberDesc:numberDesc allowsPrefixMatch:NO];
}
// Helper method to get the region code for a given phone number, from a list of possible region
// codes. If the list contains more than one region, the first region for which the number is
// valid is returned.
- (NSString *)regionCodeForShortNumber:(NBPhoneNumber *)number
fromRegionList:(NSArray<NSString *> *)regionCodes {
if (regionCodes.count == 0) {
return nil;
} else if (regionCodes.count == 1) {
return regionCodes[0];
}
NSString *nationalNumber = [self getNationalSignificantNumber:number];
for (NSString *regionCode in regionCodes) {
NBPhoneMetaData *metadata = [self.helper shortNumberMetadataForRegion:regionCode];
if (metadata != nil && [self matchesPossibleNumber:nationalNumber
andNationalNumber:metadata.shortCode]) {
// The number is valid for this region.
return regionCode;
}
}
return nil;
}
- (BOOL)doesRegionDialingFrom:(NSString *)regionCode
matchesPhoneNumber:(NBPhoneNumber *)phoneNumber {
NSArray<NSString *> *regionCodes = [self getRegionCodesForCountryCode:phoneNumber.countryCode];
return [regionCodes containsObject:regionCode];
}
- (BOOL)matchesEmergencyNumberHelper:(NSString *)number regionCode:(NSString *)regionCode
allowsPrefixMatch:(BOOL)allowsPrefixMatch {
NSString *possibleNumber = [self extractPossibleNumber:number];
NSRegularExpression *regex =
[[NBRegularExpressionCache sharedInstance] regularExpressionForPattern:PLUS_CHARS_PATTERN
error:NULL];
NSTextCheckingResult *result = [regex firstMatchInString:possibleNumber
options:kNilOptions
range:NSMakeRange(0, possibleNumber.length)];
if (result != nil) {
// Returns false if the number starts with a plus sign. We don't believe dialing the country
// code before emergency numbers (e.g. +1911) works, but later, if that proves to work, we can
// add additional logic here to handle it.
return NO;
}
NBPhoneMetaData *metadata = [self.helper shortNumberMetadataForRegion:regionCode];
if (metadata == nil || metadata.emergency == nil) {
return NO;
}
NSString *normalizedNumber = [self normalizeDigitsOnly:possibleNumber];
NSSet<NSString *> *exactRegions = [NBPhoneNumberUtil regionsWhereEmergencyNumbersMustBeExact];
BOOL allowsPrefixMatchForRegion = allowsPrefixMatch && ![exactRegions containsObject:regionCode];
return [self.matcher matchNationalNumber:normalizedNumber
phoneNumberDesc:metadata.emergency
allowsPrefixMatch:allowsPrefixMatchForRegion];
}
@end
#endif // SHORT_NUMBER_SUPPORT

View File

@ -9,14 +9,11 @@
#import <Foundation/Foundation.h>
#import "NBPhoneNumberDefines.h"
@class NBPhoneMetaData, NBPhoneNumber, NBMetadataHelper;
@class NBPhoneMetaData, NBPhoneNumber;
@interface NBPhoneNumberUtil : NSObject
+ (NBPhoneNumberUtil *)sharedInstance;
- (instancetype)initWithMetadataHelper:(NBMetadataHelper *)helper;
- (instancetype)init NS_UNAVAILABLE;
@property(nonatomic, strong, readonly) NSDictionary *DIGIT_MAPPINGS;
@ -39,7 +36,9 @@
- (NSString *)extractPossibleNumber:(NSString *)phoneNumber;
- (NSNumber *)extractCountryCode:(NSString *)fullNumber nationalNumber:(NSString **)nationalNumber;
#if TARGET_OS_IOS
- (NSString *)countryCodeByCarrier;
#endif
- (NSString *)getNddPrefixForRegion:(NSString *)regionCode stripNonDigits:(BOOL)stripNonDigits;
- (NSString *)getNationalSignificantNumber:(NBPhoneNumber *)phoneNumber;

View File

@ -16,8 +16,9 @@
#import "NBPhoneNumberDesc.h"
#import "NBRegExMatcher.h"
#if __has_include(<Contacts/Contacts.h>)
#import "Contacts/Contacts.h"
#if TARGET_OS_IOS
#import <CoreTelephony/CTCarrier.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#endif
static NSString *NormalizeNonBreakingSpace(NSString *aString) {
@ -39,8 +40,11 @@ static BOOL isNan(NSString *sourceString) {
@interface NBPhoneNumberUtil ()
@property(nonatomic, strong) NSCache<NSString *, NSRegularExpression *> *entireStringRegexCache;
@property(nonatomic, strong) NSCache<NSString *, NSRegularExpression *> *regexPatternCache;
@property(nonatomic, strong) NSLock *entireStringCacheLock;
@property(nonatomic, strong) NSMutableDictionary *entireStringRegexCache;
@property(nonatomic, strong) NSLock *lockPatternCache;
@property(nonatomic, strong) NSMutableDictionary *regexPatternCache;
@property(nonatomic, strong) NSRegularExpression *CAPTURING_DIGIT_PATTERN;
@property(nonatomic, strong) NSRegularExpression *VALID_ALPHA_PHONE_PATTERN;
@ -48,6 +52,10 @@ static BOOL isNan(NSString *sourceString) {
@property(nonatomic, strong, readwrite) NBMetadataHelper *helper;
@property(nonatomic, strong, readwrite) NBRegExMatcher *matcher;
#if TARGET_OS_IOS
@property(nonatomic, readonly) CTTelephonyNetworkInfo *telephonyNetworkInfo;
#endif
@end
@implementation NBPhoneNumberUtil
@ -111,24 +119,11 @@ static NSArray *GEO_MOBILE_COUNTRIES;
static NBPhoneNumberUtil *sharedOnceInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedOnceInstance = [[self alloc] initWithMetadataHelper:[[NBMetadataHelper alloc] init]];
sharedOnceInstance = [[self alloc] init];
});
return sharedOnceInstance;
}
- (instancetype)initWithMetadataHelper:(NBMetadataHelper *)helper {
self = [super init];
if (self != nil) {
_regexPatternCache = [[NSCache alloc] init];
_entireStringRegexCache = [[NSCache alloc] init];
_helper = helper;
_matcher = [[NBRegExMatcher alloc] init];
[self initRegularExpressionSet];
[self initNormalizationMappings];
}
return self;
}
#pragma mark - NSError
- (NSError *)errorWithObject:(id)obj withDomain:(NSString *)domain {
@ -140,37 +135,55 @@ static NSArray *GEO_MOBILE_COUNTRIES;
- (NSRegularExpression *)entireRegularExpressionWithPattern:(NSString *)regexPattern
options:(NSRegularExpressionOptions)options
error:(NSError **)error {
NSRegularExpression *regex = [_entireStringRegexCache objectForKey:regexPattern];
if (!regex) {
NSString *finalRegexString = regexPattern;
if ([regexPattern rangeOfString:@"^"].location == NSNotFound) {
finalRegexString = [NSString stringWithFormat:@"^(?:%@)$", regexPattern];
[_entireStringCacheLock lock];
@try {
if (!_entireStringRegexCache) {
_entireStringRegexCache = [[NSMutableDictionary alloc] init];
}
regex = [self regularExpressionWithPattern:finalRegexString options:0 error:error];
[_entireStringRegexCache setObject:regex forKey:regexPattern];
}
NSRegularExpression *regex = [_entireStringRegexCache objectForKey:regexPattern];
if (!regex) {
NSString *finalRegexString = regexPattern;
if ([regexPattern rangeOfString:@"^"].location == NSNotFound) {
finalRegexString = [NSString stringWithFormat:@"^(?:%@)$", regexPattern];
}
return regex;
regex = [self regularExpressionWithPattern:finalRegexString options:0 error:error];
[_entireStringRegexCache setObject:regex forKey:regexPattern];
}
return regex;
} @finally {
[_entireStringCacheLock unlock];
}
}
- (NSRegularExpression *)regularExpressionWithPattern:(NSString *)pattern
options:(NSRegularExpressionOptions)options
error:(NSError **)error {
NSRegularExpression *regex = [_regexPatternCache objectForKey:pattern];
if (!regex) {
regex = [NSRegularExpression regularExpressionWithPattern:pattern
options:options
error:error];
[_regexPatternCache setObject:regex forKey:pattern];
[_lockPatternCache lock];
@try {
if (!_regexPatternCache) {
_regexPatternCache = [[NSMutableDictionary alloc] init];
}
NSRegularExpression *regex = [_regexPatternCache objectForKey:pattern];
if (!regex) {
regex =
[NSRegularExpression regularExpressionWithPattern:pattern options:options error:error];
[_regexPatternCache setObject:regex forKey:pattern];
}
return regex;
} @finally {
[_lockPatternCache unlock];
}
return regex;
}
- (NSMutableArray *)componentsSeparatedByRegex:(NSString *)sourceString regex:(NSString *)pattern {
NSString *replacedString = [self replaceStringByRegex:sourceString
regex:pattern
withTemplate:@"<SEP>"];
NSString *replacedString =
[self replaceStringByRegex:sourceString regex:pattern withTemplate:@"<SEP>"];
NSMutableArray *resArray = [[replacedString componentsSeparatedByString:@"<SEP>"] mutableCopy];
[resArray removeObject:@""];
return resArray;
@ -182,9 +195,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
}
NSError *error = nil;
NSRegularExpression *currentPattern = [self regularExpressionWithPattern:pattern
options:0
error:&error];
NSRegularExpression *currentPattern =
[self regularExpressionWithPattern:pattern options:0 error:&error];
NSArray *matches = [currentPattern matchesInString:sourceString
options:0
range:NSMakeRange(0, sourceString.length)];
@ -214,9 +226,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
NSString *replacementResult = [sourceString copy];
NSError *error = nil;
NSRegularExpression *currentPattern = [self regularExpressionWithPattern:pattern
options:0
error:&error];
NSRegularExpression *currentPattern =
[self regularExpressionWithPattern:pattern options:0 error:&error];
NSRange replaceRange =
[currentPattern rangeOfFirstMatchInString:sourceString
options:0
@ -236,9 +247,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
regex:(NSString *)pattern
withTemplate:(NSString *)templateString {
NSError *error = nil;
NSRegularExpression *currentPattern = [self regularExpressionWithPattern:pattern
options:0
error:&error];
NSRegularExpression *currentPattern =
[self regularExpressionWithPattern:pattern options:0 error:&error];
NSArray *matches = [currentPattern matchesInString:sourceString
options:0
range:NSMakeRange(0, sourceString.length)];
@ -274,9 +284,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
- (NSTextCheckingResult *)matchFirstByRegex:(NSString *)sourceString regex:(NSString *)pattern {
NSError *error = nil;
NSRegularExpression *currentPattern = [self regularExpressionWithPattern:pattern
options:0
error:&error];
NSRegularExpression *currentPattern =
[self regularExpressionWithPattern:pattern options:0 error:&error];
NSArray *matches = [currentPattern matchesInString:sourceString
options:0
range:NSMakeRange(0, sourceString.length)];
@ -286,9 +295,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
- (NSArray *)matchesByRegex:(NSString *)sourceString regex:(NSString *)pattern {
NSError *error = nil;
NSRegularExpression *currentPattern = [self regularExpressionWithPattern:pattern
options:0
error:&error];
NSRegularExpression *currentPattern =
[self regularExpressionWithPattern:pattern options:0 error:&error];
NSArray *matches = [currentPattern matchesInString:sourceString
options:0
range:NSMakeRange(0, sourceString.length)];
@ -309,9 +317,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
- (BOOL)isStartingStringByRegex:(NSString *)sourceString regex:(NSString *)pattern {
NSError *error = nil;
NSRegularExpression *currentPattern = [self regularExpressionWithPattern:pattern
options:0
error:&error];
NSRegularExpression *currentPattern =
[self regularExpressionWithPattern:pattern options:0 error:&error];
NSArray *matches = [currentPattern matchesInString:sourceString
options:0
range:NSMakeRange(0, sourceString.length)];
@ -394,6 +401,20 @@ static NSArray *GEO_MOBILE_COUNTRIES;
GEO_MOBILE_COUNTRIES = @[ @52, @54, @55 ];
}
- (instancetype)init {
self = [super init];
if (self) {
_lockPatternCache = [[NSLock alloc] init];
_entireStringCacheLock = [[NSLock alloc] init];
_helper = [[NBMetadataHelper alloc] init];
_matcher = [[NBRegExMatcher alloc] init];
[self initRegularExpressionSet];
[self initNormalizationMappings];
}
return self;
}
- (void)initRegularExpressionSet {
NSError *error = nil;
@ -405,42 +426,40 @@ static NSArray *GEO_MOBILE_COUNTRIES;
}
if (!_VALID_ALPHA_PHONE_PATTERN) {
_VALID_ALPHA_PHONE_PATTERN = [self regularExpressionWithPattern:VALID_ALPHA_PHONE_PATTERN_STRING
options:0
error:&error];
_VALID_ALPHA_PHONE_PATTERN =
[self regularExpressionWithPattern:VALID_ALPHA_PHONE_PATTERN_STRING options:0 error:&error];
}
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *EXTN_PATTERNS_FOR_PARSING =
@"(?:;ext=([0-9-٠-٩۰-۹]{1,7})|[ "
@"\\t,]*(?:e?xt(?:ensi(?:ó?|ó))?n?|??|[,xX#~]|int|anexo|)[:\\.]?["
@" \\t,-]*([0-9-٠-٩۰-۹]{1,7})#?|[- ]+([0-9-٠-٩۰-۹]{1,5})#)$";
dispatch_once(
&onceToken, ^{
NSString *EXTN_PATTERNS_FOR_PARSING =
@"(?:;ext=([0-9-٠-٩۰-۹]{1,7})|[ "
@"\\t,]*(?:e?xt(?:ensi(?:ó?|ó))?n?|??|[,xX#~]|int|anexo|)[:\\.]?["
@" \\t,-]*([0-9-٠-٩۰-۹]{1,7})#?|[- ]+([0-9-٠-٩۰-۹]{1,5})#)$";
LEADING_PLUS_CHARS_PATTERN = [NSString stringWithFormat:@"^[%@]+", NB_PLUS_CHARS];
LEADING_PLUS_CHARS_PATTERN = [NSString stringWithFormat:@"^[%@]+", NB_PLUS_CHARS];
VALID_START_CHAR_PATTERN =
[NSString stringWithFormat:@"[%@%@]", NB_PLUS_CHARS, NB_VALID_DIGITS_STRING];
VALID_START_CHAR_PATTERN =
[NSString stringWithFormat:@"[%@%@]", NB_PLUS_CHARS, NB_VALID_DIGITS_STRING];
SECOND_NUMBER_START_PATTERN = @"[\\\\\\/] *x";
SECOND_NUMBER_START_PATTERN = @"[\\\\\\/] *x";
UNWANTED_END_CHAR_PATTERN =
[NSString stringWithFormat:@"[^%@%@#]+$", NB_VALID_DIGITS_STRING, VALID_ALPHA];
UNWANTED_END_CHAR_PATTERN =
[NSString stringWithFormat:@"[^%@%@#]+$", NB_VALID_DIGITS_STRING, VALID_ALPHA];
EXTN_PATTERN = [NSString stringWithFormat:@"(?:%@)$", EXTN_PATTERNS_FOR_PARSING];
EXTN_PATTERN = [NSString stringWithFormat:@"(?:%@)$", EXTN_PATTERNS_FOR_PARSING];
SEPARATOR_PATTERN = [NSString stringWithFormat:@"[%@]+", VALID_PUNCTUATION];
SEPARATOR_PATTERN = [NSString stringWithFormat:@"[%@]+", VALID_PUNCTUATION];
VALID_PHONE_NUMBER_PATTERN =
@"^[0-9-٠-٩۰-۹]{2}$|^[+]*(?:[-x-―−ー-- "
@"­ ().\\[\\]/"
@"~*]*[0-9-٠-٩۰-۹]){3,}[-x-―−ー-- "
@" "
@"­ ().\\[\\]/"
@"~*A-Za-z0-9-٠-٩۰-۹]*(?:;ext=([0-9-٠-٩۰-۹]{1,7})|[ "
@"\\t,]*(?:e?xt(?:ensi(?:ó?|ó))?n?|??|[,x#~]|int|anexo|)[:\\.]?[ "
@" \\t,-]*([0-9-٠-٩۰-۹]{1,7})#?|[- ]+([0-9-٠-٩۰-۹]{1,5})#)?$";
});
VALID_PHONE_NUMBER_PATTERN =
@"^[0-9-٠-٩۰-۹]{2}$|^[+]*(?:[-x-―−ー-- "
@"­ ().\\[\\]/~*]*[0-9-٠-٩۰-۹]){3,}[-x-―−ー-- "
@"­ ().\\[\\]/"
@"~*A-Za-z0-9-٠-٩۰-۹]*(?:;ext=([0-9-٠-٩۰-۹]{1,7})|[ "
@"\\t,]*(?:e?xt(?:ensi(?:ó?|ó))?n?|??|[,x#~]|int|anexo|)[:\\.]?[ "
@" \\t,-]*([0-9-٠-٩۰-۹]{1,7})#?|[- ]+([0-9-٠-٩۰-۹]{1,5})#)?$";
});
}
- (NSDictionary *)DIGIT_MAPPINGS {
@ -524,8 +543,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
@".", @".", @".", @"\uFF0E", nil];
MOBILE_TOKEN_MAPPINGS = @{
@52 : @"1",
@54 : @"9",
@52: @"1",
@54: @"9",
};
});
}
@ -557,13 +576,12 @@ static NSArray *GEO_MOBILE_COUNTRIES;
if (start >= 0) {
possibleNumber = [number substringFromIndex:start];
// Remove trailing non-alpha non-numerical characters.
possibleNumber = [self replaceStringByRegex:possibleNumber
regex:UNWANTED_END_CHAR_PATTERN
withTemplate:@""];
possibleNumber =
[self replaceStringByRegex:possibleNumber regex:UNWANTED_END_CHAR_PATTERN withTemplate:@""];
// Check for extra numbers at the end.
int secondNumberStart = [self stringPositionByRegex:possibleNumber
regex:SECOND_NUMBER_START_PATTERN];
int secondNumberStart =
[self stringPositionByRegex:possibleNumber regex:SECOND_NUMBER_START_PATTERN];
if (secondNumberStart > 0) {
possibleNumber = [possibleNumber substringWithRange:NSMakeRange(0, secondNumberStart)];
}
@ -741,8 +759,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
@try {
res = [self getLengthOfGeographicalAreaCode:phoneNumber];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) {
(*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
@ -814,8 +832,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
@try {
res = [self getLengthOfNationalDestinationCode:phoneNumber];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) {
(*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
@ -834,8 +852,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
copiedProto = phoneNumber;
}
NSString *nationalSignificantNumber = [self format:copiedProto
numberFormat:NBEPhoneNumberFormatINTERNATIONAL];
NSString *nationalSignificantNumber =
[self format:copiedProto numberFormat:NBEPhoneNumberFormatINTERNATIONAL];
NSMutableArray *numberGroups = [[self componentsSeparatedByRegex:nationalSignificantNumber
regex:NON_DIGITS_PATTERN] mutableCopy];
@ -854,7 +872,7 @@ static NSArray *GEO_MOBILE_COUNTRIES;
return 0;
}
NSArray *regionCodes = [self.helper regionCodeFromCountryCode:phoneNumber.countryCode];
NSArray *regionCodes = [NBMetadataHelper regionCodeFromCountryCode:phoneNumber.countryCode];
BOOL isExists = NO;
for (NSString *regCode in regionCodes) {
@ -879,11 +897,11 @@ static NSArray *GEO_MOBILE_COUNTRIES;
}
- (NSString *)getCountryMobileTokenFromCountryCode:(NSInteger)countryCallingCode {
NSString *mobileToken = MOBILE_TOKEN_MAPPINGS[@(countryCallingCode)];
if (mobileToken != nil) {
return mobileToken;
}
return @"";
NSString *mobileToken = MOBILE_TOKEN_MAPPINGS[@(countryCallingCode)];
if (mobileToken != nil) {
return mobileToken;
}
return @"";
}
/**
@ -987,7 +1005,7 @@ static NSArray *GEO_MOBILE_COUNTRIES;
* @private
*/
- (BOOL)hasValidCountryCallingCode:(NSNumber *)countryCallingCode {
id res = [self.helper regionCodeFromCountryCode:countryCallingCode];
id res = [NBMetadataHelper regionCodeFromCountryCode:countryCallingCode];
if (res != nil) {
return YES;
}
@ -1019,8 +1037,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
@try {
res = [self format:phoneNumber numberFormat:numberFormat];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
return res;
@ -1062,17 +1080,16 @@ static NSArray *GEO_MOBILE_COUNTRIES;
// for regions which share a country calling code is contained by only one
// region for performance reasons. For example, for NANPA regions it will be
// contained in the metadata for US.
NSArray *regionCodeArray = [self.helper regionCodeFromCountryCode:countryCallingCode];
NSArray *regionCodeArray = [NBMetadataHelper regionCodeFromCountryCode:countryCallingCode];
NSString *regionCode = [regionCodeArray objectAtIndex:0];
// Metadata cannot be nil because the country calling code is valid (which
// means that the region code cannot be ZZ and must be one of our supported
// region codes).
NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCallingCode
regionCode:regionCode];
NSString *formattedExtension = [self maybeGetFormattedExtension:phoneNumber
metadata:metadata
numberFormat:numberFormat];
NBPhoneMetaData *metadata =
[self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:regionCode];
NSString *formattedExtension =
[self maybeGetFormattedExtension:phoneNumber metadata:metadata numberFormat:numberFormat];
NSString *formattedNationalNumber = [self formatNsn:nationalSignificantNumber
metadata:metadata
phoneNumberFormat:numberFormat
@ -1110,8 +1127,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
numberFormat:numberFormat
userDefinedFormats:userDefinedFormats];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
return res;
@ -1131,7 +1148,7 @@ static NSArray *GEO_MOBILE_COUNTRIES;
// for regions which share a country calling code is contained by only one
// region for performance reasons. For example, for NANPA regions it will be
// contained in the metadata for US.
NSArray *regionCodes = [self.helper regionCodeFromCountryCode:countryCallingCode];
NSArray *regionCodes = [NBMetadataHelper regionCodeFromCountryCode:countryCallingCode];
NSString *regionCode = nil;
if (regionCodes != nil && regionCodes.count > 0) {
regionCode = [regionCodes objectAtIndex:0];
@ -1139,8 +1156,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
// Metadata cannot be nil because the country calling code is valid
/** @type {i18n.phonenumbers.PhoneMetadata} */
NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCallingCode
regionCode:regionCode];
NBPhoneMetaData *metadata =
[self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:regionCode];
NSString *formattedNumber = @"";
NBNumberFormat *formattingPattern =
@ -1181,9 +1198,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
carrierCode:nil];
}
NSString *formattedExtension = [self maybeGetFormattedExtension:number
metadata:metadata
numberFormat:numberFormat];
NSString *formattedExtension =
[self maybeGetFormattedExtension:number metadata:metadata numberFormat:numberFormat];
// NSLog(@"!@# prefixNumberWithCountryCallingCode called [%@]", formattedExtension);
return [self prefixNumberWithCountryCallingCode:countryCallingCode
@ -1212,8 +1228,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
@try {
res = [self formatNationalNumberWithCarrierCode:number carrierCode:carrierCode];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) {
(*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
@ -1236,8 +1252,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
// contained in the metadata for US.
NSString *regionCode = [self getRegionCodeForCountryCode:countryCallingCode];
// Metadata cannot be nil because the country calling code is valid.
NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCallingCode
regionCode:regionCode];
NBPhoneMetaData *metadata =
[self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:regionCode];
NSString *formattedExtension = [self maybeGetFormattedExtension:number
metadata:metadata
numberFormat:NBEPhoneNumberFormatNATIONAL];
@ -1293,8 +1309,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
@try {
res = [self formatNationalNumberWithCarrierCode:number carrierCode:fallbackCarrierCode];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) {
(*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
@ -1334,8 +1350,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
regionCallingFrom:regionCallingFrom
withFormatting:withFormatting];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
return res;
@ -1435,8 +1451,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
@try {
res = [self formatOutOfCountryCallingNumber:number regionCallingFrom:regionCallingFrom];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
@ -1460,9 +1476,9 @@ static NSArray *GEO_MOBILE_COUNTRIES;
if ([self isNANPACountry:regionCallingFrom]) {
// For NANPA regions, return the national format for these regions but
// prefix it with the country calling code.
return [NSString stringWithFormat:@"%@ %@", countryCallingCode,
[self format:number
numberFormat:NBEPhoneNumberFormatNATIONAL]];
return [NSString
stringWithFormat:@"%@ %@", countryCallingCode,
[self format:number numberFormat:NBEPhoneNumberFormatNATIONAL]];
}
} else if ([countryCallingCode
isEqualToNumber:[self getCountryCodeForValidRegion:regionCallingFrom error:nil]]) {
@ -1496,8 +1512,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
NSString *regionCode = [self getRegionCodeForCountryCode:countryCallingCode];
// Metadata cannot be nil because the country calling code is valid.
NBPhoneMetaData *metadataForRegion = [self getMetadataForRegionOrCallingCode:countryCallingCode
regionCode:regionCode];
NBPhoneMetaData *metadataForRegion =
[self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:regionCode];
NSString *formattedNationalNumber = [self formatNsn:nationalSignificantNumber
metadata:metadataForRegion
phoneNumberFormat:NBEPhoneNumberFormatINTERNATIONAL
@ -1575,8 +1591,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
@try {
res = [self formatInOriginalFormat:number regionCallingFrom:regionCallingFrom];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
@ -1603,12 +1619,12 @@ static NSArray *GEO_MOBILE_COUNTRIES;
formattedNumber = [self format:number numberFormat:NBEPhoneNumberFormatINTERNATIONAL];
break;
case NBECountryCodeSourceFROM_NUMBER_WITH_IDD:
formattedNumber = [self formatOutOfCountryCallingNumber:number
regionCallingFrom:regionCallingFrom];
formattedNumber =
[self formatOutOfCountryCallingNumber:number regionCallingFrom:regionCallingFrom];
break;
case NBECountryCodeSourceFROM_NUMBER_WITHOUT_PLUS_SIGN:
formattedNumber = [[self format:number
numberFormat:NBEPhoneNumberFormatINTERNATIONAL] substringFromIndex:1];
formattedNumber = [[self format:number numberFormat:NBEPhoneNumberFormatINTERNATIONAL]
substringFromIndex:1];
break;
case NBECountryCodeSourceFROM_DEFAULT_COUNTRY:
// Fall-through to default case.
@ -1752,16 +1768,16 @@ static NSArray *GEO_MOBILE_COUNTRIES;
- (BOOL)hasFormattingPatternForNumber:(NBPhoneNumber *)number {
NSNumber *countryCallingCode = number.countryCode;
NSString *phoneNumberRegion = [self getRegionCodeForCountryCode:countryCallingCode];
NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCallingCode
regionCode:phoneNumberRegion];
NBPhoneMetaData *metadata =
[self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:phoneNumberRegion];
if (metadata == nil) {
return NO;
}
NSString *nationalNumber = [self getNationalSignificantNumber:number];
NBNumberFormat *formatRule = [self chooseFormattingPatternForNumber:metadata.numberFormats
nationalNumber:nationalNumber];
NBNumberFormat *formatRule =
[self chooseFormattingPatternForNumber:metadata.numberFormats nationalNumber:nationalNumber];
return formatRule != nil;
}
@ -1798,8 +1814,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
@try {
res = [self formatOutOfCountryKeepingAlphaChars:number regionCallingFrom:regionCallingFrom];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
return res;
@ -1848,8 +1864,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
return [NSString stringWithFormat:@"%@ %@", countryCode, rawInput];
}
} else if (metadataForRegionCallingFrom != nil &&
[countryCode isEqualToNumber:[self getCountryCodeForValidRegion:regionCallingFrom
error:nil]]) {
[countryCode
isEqualToNumber:[self getCountryCodeForValidRegion:regionCallingFrom error:nil]]) {
NBNumberFormat *formattingPattern =
[self chooseFormattingPatternForNumber:metadataForRegionCallingFrom.numberFormats
nationalNumber:nationalNumber];
@ -1892,8 +1908,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
NSString *regionCode = [self getRegionCodeForCountryCode:countryCode];
// Metadata cannot be nil because the country calling code is valid.
NBPhoneMetaData *metadataForRegion = [self getMetadataForRegionOrCallingCode:countryCode
regionCode:regionCode];
NBPhoneMetaData *metadataForRegion =
[self getMetadataForRegionOrCallingCode:countryCode regionCode:regionCode];
NSString *formattedExtension =
[self maybeGetFormattedExtension:number
metadata:metadataForRegion
@ -1940,8 +1956,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
([intlNumberFormats count] <= 0 || numberFormat == NBEPhoneNumberFormatNATIONAL)
? metadata.numberFormats
: intlNumberFormats;
NBNumberFormat *formattingPattern = [self chooseFormattingPatternForNumber:availableFormats
nationalNumber:phoneNumber];
NBNumberFormat *formattingPattern =
[self chooseFormattingPatternForNumber:availableFormats nationalNumber:phoneNumber];
if (formattingPattern == nil) {
return phoneNumber;
@ -2059,9 +2075,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
* instead.
*/
- (NBPhoneNumber *)getExampleNumber:(NSString *)regionCode error:(NSError *__autoreleasing *)error {
NBPhoneNumber *res = [self getExampleNumberForType:regionCode
type:NBEPhoneNumberTypeFIXED_LINE
error:error];
NBPhoneNumber *res =
[self getExampleNumberForType:regionCode type:NBEPhoneNumberTypeFIXED_LINE error:error];
return res;
}
@ -2086,8 +2101,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
return nil;
}
NBPhoneNumberDesc *desc = [self getNumberDescByType:[self.helper getMetadataForRegion:regionCode]
type:type];
NBPhoneNumberDesc *desc =
[self getNumberDescByType:[self.helper getMetadataForRegion:regionCode] type:type];
if ([NBMetadataHelper hasValue:desc.exampleNumber]) {
return [self parse:desc.exampleNumber defaultRegion:regionCode error:error];
@ -2218,8 +2233,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
*/
- (NBEPhoneNumberType)getNumberType:(NBPhoneNumber *)phoneNumber {
NSString *regionCode = [self getRegionCodeForNumber:phoneNumber];
NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:phoneNumber.countryCode
regionCode:regionCode];
NBPhoneMetaData *metadata =
[self getMetadataForRegionOrCallingCode:phoneNumber.countryCode regionCode:regionCode];
if (metadata == nil) {
return NBEPhoneNumberTypeUNKNOWN;
}
@ -2348,8 +2363,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
*/
- (BOOL)isValidNumberForRegion:(NBPhoneNumber *)number regionCode:(NSString *)regionCode {
NSNumber *countryCode = [number.countryCode copy];
NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCode
regionCode:regionCode];
NBPhoneMetaData *metadata =
[self getMetadataForRegionOrCallingCode:countryCode regionCode:regionCode];
if (metadata == nil ||
([NB_REGION_CODE_FOR_NON_GEO_ENTITY isEqualToString:regionCode] == NO &&
![countryCode isEqualToNumber:[self getCountryCodeForValidRegion:regionCode error:nil]])) {
@ -2371,8 +2386,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
return numberLength > MIN_LENGTH_FOR_NSN_ && numberLength <= MAX_LENGTH_FOR_NSN_;
}
return [self getNumberTypeHelper:nationalSignificantNumber
metadata:metadata] != NBEPhoneNumberTypeUNKNOWN;
return [self getNumberTypeHelper:nationalSignificantNumber metadata:metadata] !=
NBEPhoneNumberTypeUNKNOWN;
}
/**
@ -2389,7 +2404,7 @@ static NSArray *GEO_MOBILE_COUNTRIES;
return nil;
}
NSArray *regionCodes = [self.helper regionCodeFromCountryCode:phoneNumber.countryCode];
NSArray *regionCodes = [NBMetadataHelper regionCodeFromCountryCode:phoneNumber.countryCode];
if (regionCodes == nil || [regionCodes count] <= 0) {
return nil;
}
@ -2423,8 +2438,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
if ([self stringPositionByRegex:nationalNumber regex:metadata.leadingDigits] == 0) {
return regionCode;
}
} else if ([self getNumberTypeHelper:nationalNumber
metadata:metadata] != NBEPhoneNumberTypeUNKNOWN) {
} else if ([self getNumberTypeHelper:nationalNumber metadata:metadata] !=
NBEPhoneNumberTypeUNKNOWN) {
return regionCode;
}
}
@ -2442,7 +2457,7 @@ static NSArray *GEO_MOBILE_COUNTRIES;
* @return {string}
*/
- (NSString *)getRegionCodeForCountryCode:(NSNumber *)countryCallingCode {
NSArray *regionCodes = [self.helper regionCodeFromCountryCode:countryCallingCode];
NSArray *regionCodes = [NBMetadataHelper regionCodeFromCountryCode:countryCallingCode];
return regionCodes == nil ? NB_UNKNOWN_REGION : [regionCodes objectAtIndex:0];
}
@ -2456,7 +2471,7 @@ static NSArray *GEO_MOBILE_COUNTRIES;
* @return {Array.<string>}
*/
- (NSArray *)getRegionCodesForCountryCode:(NSNumber *)countryCallingCode {
NSArray *regionCodes = [self.helper regionCodeFromCountryCode:countryCallingCode];
NSArray *regionCodes = [NBMetadataHelper regionCodeFromCountryCode:countryCallingCode];
return regionCodes == nil ? nil : regionCodes;
}
@ -2560,7 +2575,7 @@ static NSArray *GEO_MOBILE_COUNTRIES;
*/
- (BOOL)isNANPACountry:(NSString *)regionCode {
BOOL isExists = NO;
NSArray *res = [self.helper
NSArray *res = [NBMetadataHelper
regionCodeFromCountryCode:[NSNumber numberWithUnsignedInteger:NANPA_COUNTRY_CODE_]];
for (NSString *inRegionCode in res) {
@ -2628,8 +2643,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
@try {
res = [self isPossibleNumber:number];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
return res;
@ -2673,8 +2688,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
// non-geographical entities), so we just check mobile.
return [self validateNumberLength:number metadata:metadata type:NBEPhoneNumberTypeMOBILE];
} else {
NBPhoneNumberDesc *mobileDesc = [self getNumberDescByType:metadata
type:NBEPhoneNumberTypeMOBILE];
NBPhoneNumberDesc *mobileDesc =
[self getNumberDescByType:metadata type:NBEPhoneNumberTypeMOBILE];
if ([self descHasPossibleNumberData:mobileDesc]) {
// Merge the mobile data in if there was any. We have to make a copy to do this.
// Note that when adding the possible lengths from mobile, we have to again check they
@ -2808,8 +2823,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
@try {
res = [self isPossibleNumberWithReason:number];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
@ -2830,8 +2845,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
NSString *regionCode = [self getRegionCodeForCountryCode:countryCode];
// Metadata cannot be nil because the country calling code is valid.
NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCode
regionCode:regionCode];
NBPhoneMetaData *metadata =
[self getMetadataForRegionOrCallingCode:countryCode regionCode:regionCode];
return [self testNumberLength:nationalNumber desc:metadata.generalDesc];
}
@ -2863,9 +2878,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
error:(NSError **)error {
number = NormalizeNonBreakingSpace(number);
BOOL res = [self isPossibleNumber:[self parse:number
defaultRegion:regionDialingFrom
error:error]];
BOOL res =
[self isPossibleNumber:[self parse:number defaultRegion:regionDialingFrom error:error]];
return res;
}
@ -2929,7 +2943,7 @@ static NSArray *GEO_MOBILE_COUNTRIES;
NSString *subNumber = [fullNumber substringWithRange:NSMakeRange(0, i)];
NSNumber *potentialCountryCode = [NSNumber numberWithInteger:[subNumber integerValue]];
NSArray *regionCodes = [self.helper regionCodeFromCountryCode:potentialCountryCode];
NSArray *regionCodes = [NBMetadataHelper regionCodeFromCountryCode:potentialCountryCode];
if (regionCodes != nil && regionCodes.count > 0) {
if (nationalNumber != NULL) {
if ((*nationalNumber) == nil) {
@ -2953,7 +2967,7 @@ static NSArray *GEO_MOBILE_COUNTRIES;
*/
- (NSArray *)getSupportedRegions {
NSArray *allKeys = [[self.helper countryCodeToCountryNumberDictionary] allKeys];
NSArray *allKeys = [[NBMetadataHelper CCode2CNMap] allKeys];
NSPredicate *predicateIsNaN =
[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return isNan(evaluatedObject);
@ -3074,8 +3088,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
return @0;
}
NSNumber *potentialCountryCode = [self extractCountryCode:fullNumber
nationalNumber:nationalNumber];
NSNumber *potentialCountryCode =
[self extractCountryCode:fullNumber nationalNumber:nationalNumber];
if (![potentialCountryCode isEqualToNumber:@0]) {
(*phoneNumber).countryCode = potentialCountryCode;
@ -3160,11 +3174,11 @@ static NSArray *GEO_MOBILE_COUNTRIES;
return NO;
}
NSString *numberStr = [(*number) copy];
NSString *numberStr = [(*number)copy];
if ([self stringPositionByRegex:numberStr regex:iddPattern] == 0) {
NSTextCheckingResult *matched = [[self matchesByRegex:numberStr
regex:iddPattern] objectAtIndex:0];
NSTextCheckingResult *matched =
[[self matchesByRegex:numberStr regex:iddPattern] objectAtIndex:0];
NSString *matchedString = [numberStr substringWithRange:matched.range];
NSUInteger matchEnd = matchedString.length;
NSString *remainString = [numberStr substringFromIndex:matchEnd];
@ -3213,9 +3227,9 @@ static NSArray *GEO_MOBILE_COUNTRIES;
}
// Check to see if the number begins with one or more plus signs.
if ([self isStartingStringByRegex:(*numberStr) regex:LEADING_PLUS_CHARS_PATTERN]) {
if ([self isStartingStringByRegex:(*numberStr)regex:LEADING_PLUS_CHARS_PATTERN]) {
(*numberStr) =
[self replaceStringByRegex:(*numberStr) regex:LEADING_PLUS_CHARS_PATTERN withTemplate:@""];
[self replaceStringByRegex:(*numberStr)regex:LEADING_PLUS_CHARS_PATTERN withTemplate:@""];
// Can now normalize the rest of the number since we've consumed the '+'
// sign at the start.
(*numberStr) = [self normalize:(*numberStr)];
@ -3250,7 +3264,7 @@ static NSArray *GEO_MOBILE_COUNTRIES;
return NO;
}
NSString *numberStr = [(*number) copy];
NSString *numberStr = [(*number)copy];
NSUInteger numberLength = numberStr.length;
NSString *possibleNationalPrefix = metadata.nationalPrefixForParsing;
@ -3262,13 +3276,11 @@ static NSArray *GEO_MOBILE_COUNTRIES;
// Attempt to parse the first digits as a national prefix.
NSString *prefixPattern = [NSString stringWithFormat:@"^(?:%@)", possibleNationalPrefix];
NSError *error = nil;
NSRegularExpression *currentPattern = [self regularExpressionWithPattern:prefixPattern
options:0
error:&error];
NSRegularExpression *currentPattern =
[self regularExpressionWithPattern:prefixPattern options:0 error:&error];
NSArray *prefixMatcher = [currentPattern matchesInString:numberStr
options:0
range:NSMakeRange(0, numberLength)];
NSArray *prefixMatcher =
[currentPattern matchesInString:numberStr options:0 range:NSMakeRange(0, numberLength)];
if (prefixMatcher && [prefixMatcher count] > 0) {
NSString *nationalNumberRule = metadata.generalDesc.nationalNumberPattern;
NSTextCheckingResult *firstMatch = [prefixMatcher objectAtIndex:0];
@ -3291,9 +3303,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
if (noTransform) {
transformedNumber = [numberStr substringFromIndex:firstMatchString.length];
} else {
transformedNumber = [self replaceFirstStringByRegex:numberStr
regex:prefixPattern
withTemplate:transformRule];
transformedNumber =
[self replaceFirstStringByRegex:numberStr regex:prefixPattern withTemplate:transformRule];
}
// If the original number was viable, and the resultant number is not,
// we return.
@ -3335,7 +3346,7 @@ static NSArray *GEO_MOBILE_COUNTRIES;
return @"";
}
NSString *numberStr = [(*number) copy];
NSString *numberStr = [(*number)copy];
int mStart = [self stringPositionByRegex:numberStr regex:EXTN_PATTERN];
// If we find a potential extension, and the number preceding this is a viable
@ -3424,27 +3435,63 @@ static NSArray *GEO_MOBILE_COUNTRIES;
}
/**
* Parses a string using the phone's carrier region (when available, uses system locale otherwise).
* This uses the country the SIM card in the phone is registered with.
* Parses a string using the phone's carrier region (when available, ZZ otherwise).
* This uses the country the sim card in the phone is registered with.
* For example if you have an AT&T sim card but are in Europe, this will parse the
* number using +1 (AT&T is a US Carrier) as the default country code.
* This also works for multi-SIM phones, using the SIM region of default voice line.
* This also works for CDMA phones which don't have a sim card.
*/
- (NBPhoneNumber *)parseWithPhoneCarrierRegion:(NSString *)numberToParse error:(NSError **)error {
numberToParse = NormalizeNonBreakingSpace(numberToParse);
NSString *defaultRegion = [self countryCodeByCarrier];
NSString *defaultRegion = nil;
#if TARGET_OS_IOS
defaultRegion = [self countryCodeByCarrier];
#else
defaultRegion = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
#endif
if ([NB_UNKNOWN_REGION isEqualToString:defaultRegion]) {
// get region from device as a failover (e.g. iPad)
NSLocale *currentLocale = [NSLocale currentLocale];
defaultRegion = [currentLocale objectForKey:NSLocaleCountryCode];
}
return [self parse:numberToParse defaultRegion:defaultRegion error:error];
}
- (NSString *)countryCodeByCarrier {
#if !TARGET_OS_TV
return [[CNContactsUserDefaults sharedDefaults].countryCode uppercaseString];
#else
return [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
#endif
#if TARGET_OS_IOS
static CTTelephonyNetworkInfo *_telephonyNetworkInfo;
- (CTTelephonyNetworkInfo *)telephonyNetworkInfo {
// cache telephony network info;
// CTTelephonyNetworkInfo objects are unnecessarily created for every call to
// parseWithPhoneCarrierRegion:error: when in reality this information not change while an app
// lives in memory real-world performance test while parsing 93 phone numbers: before change:
// 126ms after change: 32ms using static instance prevents deallocation crashes due to ios bug
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_telephonyNetworkInfo = [[CTTelephonyNetworkInfo alloc] init];
});
return _telephonyNetworkInfo;
}
- (NSString *)countryCodeByCarrier {
NSString *isoCode = [[self.telephonyNetworkInfo subscriberCellularProvider] isoCountryCode];
// The 2nd part of the if is working around an iOS 7 bug
// If the SIM card is missing, iOS 7 returns an empty string instead of nil
if (isoCode.length == 0) {
isoCode = NB_UNKNOWN_REGION;
}
return isoCode;
}
#endif
/**
* Parses a string and returns it in proto buffer format. This method differs
* from {@link #parse} in that it always populates the raw_input field of the
@ -3568,8 +3615,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
// Check the region supplied is valid, or that the extracted number starts
// with some sort of + sign so the number's region can be determined.
if (checkRegion && [self checkRegionForParsing:nationalNumber
defaultRegion:defaultRegion] == NO) {
if (checkRegion &&
[self checkRegionForParsing:nationalNumber defaultRegion:defaultRegion] == NO) {
if (error != NULL) {
(*error) = [self
errorWithObject:[NSString stringWithFormat:@"INVALID_COUNTRY_CODE:%@", defaultRegion]
@ -3639,8 +3686,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
NSString *phoneNumberRegion = [self getRegionCodeForCountryCode:countryCode];
if (phoneNumberRegion != defaultRegion) {
// Metadata cannot be nil because the country calling code is valid.
regionMetadata = [self getMetadataForRegionOrCallingCode:countryCode
regionCode:phoneNumberRegion];
regionMetadata =
[self getMetadataForRegionOrCallingCode:countryCode regionCode:phoneNumberRegion];
}
} else {
// If no extracted country calling code, use the region supplied instead.
@ -3673,8 +3720,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
[self maybeStripNationalPrefixAndCarrierCode:&potentialNationalNumber
metadata:regionMetadata
carrierCode:&carrierCode];
NBEValidationResult validationResult = [self validateNumberLength:potentialNationalNumber
metadata:regionMetadata];
NBEValidationResult validationResult =
[self validateNumberLength:potentialNationalNumber metadata:regionMetadata];
if (validationResult != NBEValidationResultTOO_SHORT &&
validationResult != NBEValidationResultIS_POSSIBLE_LOCAL_ONLY &&
validationResult != NBEValidationResultINVALID_LENGTH) {
@ -3814,8 +3861,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
@try {
res = [self isNumberMatch:firstNumberIn second:secondNumberIn];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
return res;
@ -3847,9 +3894,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
[self getRegionCodeForCountryCode:((NBPhoneNumber *)secondNumberIn).countryCode];
if (secondNumberRegion != NB_UNKNOWN_REGION) {
NSError *aNestedError;
firstNumber = [self parse:firstNumberIn
defaultRegion:secondNumberRegion
error:&aNestedError];
firstNumber =
[self parse:firstNumberIn defaultRegion:secondNumberRegion error:&aNestedError];
if (aNestedError != nil) {
return NBEMatchTypeNOT_A_NUMBER;
@ -3994,8 +4040,8 @@ static NSArray *GEO_MOBILE_COUNTRIES;
@try {
res = [self canBeInternationallyDialled:number];
} @catch (NSException *exception) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
forKey:NSLocalizedDescriptionKey];
NSDictionary *userInfo =
[NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
if (error != NULL) (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
}
return res;
@ -4029,13 +4075,11 @@ static NSArray *GEO_MOBILE_COUNTRIES;
}
NSError *error = nil;
NSRegularExpression *currentPattern = [self entireRegularExpressionWithPattern:regex
options:0
error:&error];
NSRegularExpression *currentPattern =
[self entireRegularExpressionWithPattern:regex options:0 error:&error];
NSRange stringRange = NSMakeRange(0, str.length);
NSTextCheckingResult *matchResult = [currentPattern firstMatchInString:str
options:NSMatchingAnchored
range:stringRange];
NSTextCheckingResult *matchResult =
[currentPattern firstMatchInString:str options:NSMatchingAnchored range:stringRange];
if (matchResult != nil) {
BOOL matchIsEntireString = NSEqualRanges(matchResult.range, stringRange);

View File

@ -21,7 +21,7 @@
return res;
}
- (NSString *)nb_safeStringAtIndex:(NSUInteger)index {
- (NSString *)nb_safeStringAtIndex : (NSUInteger)index {
return [self nb_safeObjectAtIndex:index class:[NSString class]];
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,97 @@
//
// NBPhoneNumberParsingPerfTest.m
// libPhoneNumberiOSTests
//
// Created by Paween Itthipalkul on 2/1/18.
// Copyright © 2018 Google LLC. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <XCTest/XCTest.h>
#import "NBMetadataHelper.h"
#import "NBPhoneMetaData.h"
#import "NBNumberFormat.h"
#import "NBPhoneNumber.h"
#import "NBPhoneNumberDesc.h"
#import "NBPhoneNumberUtil.h"
@interface NBExampleNumber: NSObject
@property (nonatomic, strong) NSString *phoneNumber;
@property (nonatomic, strong) NSString *baseRegionCode;
- (instancetype)initWithPhoneNumber:(NSString *)phoneNumber
baseRegionCode:(NSString *)baseRegionCode;
@end
@implementation NBExampleNumber
- (instancetype)initWithPhoneNumber:(NSString *)phoneNumber
baseRegionCode:(NSString *)baseRegionCode {
self = [super init];
if (self != nil) {
_phoneNumber = phoneNumber;
_baseRegionCode = baseRegionCode;
}
return self;
}
@end
@interface NBPhoneNumberParsingPerfTest: XCTestCase
@end
@implementation NBPhoneNumberParsingPerfTest
#if PERF_TEST
- (void)testParsing {
NSArray *regionCodes = [[NBMetadataHelper CCode2CNMap] allKeys];
NSMutableArray<NBExampleNumber *> *exampleNumbers = [[NSMutableArray alloc] init];
NBPhoneNumberUtil *util = [NBPhoneNumberUtil sharedInstance];
for (NSString *regionCode in regionCodes) {
NBPhoneNumber *phoneNumber = [util getExampleNumber:regionCode error:nil];
if (phoneNumber != nil) {
NSString *e164 = [util format:phoneNumber numberFormat:NBEPhoneNumberFormatE164 error:nil];
NBExampleNumber *e164Sample = [[NBExampleNumber alloc] initWithPhoneNumber:e164
baseRegionCode:regionCode];
[exampleNumbers addObject:e164Sample];
NSString *national = [util format:phoneNumber
numberFormat:NBEPhoneNumberFormatNATIONAL
error:nil];
NBExampleNumber *nationalSample = [[NBExampleNumber alloc] initWithPhoneNumber:national
baseRegionCode:regionCode];
[exampleNumbers addObject:nationalSample];
// intl format sample.
NSString *intl = [util format:phoneNumber
numberFormat:NBEPhoneNumberFormatINTERNATIONAL
error:nil];
NBExampleNumber * intlSample = [[NBExampleNumber alloc] initWithPhoneNumber:intl
baseRegionCode:regionCode];
[exampleNumbers addObject:intlSample];
}
}
for (int i = 0; i < 5; i++) {
[exampleNumbers addObjectsFromArray:exampleNumbers];
}
[self measureBlock:^{
for (NBExampleNumber *example in exampleNumbers) {
[util parseAndKeepRawInput:example.phoneNumber
defaultRegion:example.baseRegionCode
error:nil];
}
}];
}
#endif // PERF_TEST
@end

View File

@ -0,0 +1,29 @@
//
// NBPhoneNumberUtil+ShortNumberTest.h
// libPhoneNumber
//
// Created by Paween Itthipalkul on 12/1/17.
// Copyright © 2017 Google LLC. All rights reserved.
//
#import <Foundation/Foundation.h>
#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(ShortNumberTest)
- (NSString *)exampleShortNumberForCost:(NBEShortNumberCost)cost regionCode:(NSString *)regionCode;
- (NSString *)exampleShortNumberWithRegionCode:(NSString *)regionCode;
@end
NS_ASSUME_NONNULL_END
#endif // SHORT_NUMBER_SUPPORT

View File

@ -0,0 +1,53 @@
//
// NBPhoneNumberUtil+ShortNumberTest.m
// libPhoneNumber
//
// Created by Paween Itthipalkul on 12/1/17.
// Copyright © 2017 Google LLC. All rights reserved.
//
#import "NBPhoneNumberUtil+ShortNumberTest.h"
#import "NBMetadataHelper.h"
#import "NBPhoneMetadata.h"
#import "NBPhoneNumberDesc.h"
#import "NBPhoneNumberUtil+Category.h"
#if SHORT_NUMBER_SUPPORT
@implementation NBPhoneNumberUtil(ShortNumberTest)
- (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

View File

@ -0,0 +1,29 @@
//
// NBPhoneNumberUtil+ShortNumberTestHelper.h
// libPhoneNumber
//
// Created by Paween Itthipalkul on 12/1/17.
// Copyright © 2017 Google LLC. All rights reserved.
//
#import <Foundation/Foundation.h>
#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

View File

@ -0,0 +1,58 @@
//
// 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"
#if SHORT_NUMBER_SUPPORT
@interface NBPhoneNumberUtil()
@property (nonatomic, strong, readonly) NBMetadataHelper *helper;
@end
@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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,495 @@
//
// NBShortNumberInfoTest.m
// libPhoneNumber
//
// Created by Paween Itthipalkul on 11/29/17.
// Copyright © 2017 Google LLC. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "NBMetadataHelper.h"
#import "NBPhoneMetaData.h"
#import "NBPhoneNumber.h"
#import "NBPhoneNumberDesc.h"
#import "NBPhoneNumberUtil+ShortNumber.h"
#import "NBPhoneNumberUtil+ShortNumberTest.h"
#if SHORT_NUMBER_SUPPORT
@interface NBShortNumberInfoTest: XCTestCase
@end
@implementation NBShortNumberInfoTest
- (void)testMetadataParsing_US {
NBMetadataHelper *metadataHelper = [[NBMetadataHelper alloc] init];
NBPhoneMetaData *metadata = [metadataHelper shortNumberMetadataForRegion:@"US"];
XCTAssertNotNil(metadata.shortCode);
XCTAssertNotNil(metadata.standardRate);
XCTAssertNotNil(metadata.carrierSpecific);
XCTAssertNotNil(metadata.smsServices);
}
- (void)testIsPossibleShortNumber {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
NBPhoneNumber *possibleNumber = [[NBPhoneNumber alloc] init];
possibleNumber.countryCode = @33;
possibleNumber.nationalNumber = @123456;
XCTAssertTrue([util isPossibleShortNumber:possibleNumber]);
NBPhoneNumber *impossibleNumber = [[NBPhoneNumber alloc] init];
impossibleNumber.countryCode = @33;
impossibleNumber.nationalNumber = @9;
XCTAssertFalse([util isPossibleShortNumber:impossibleNumber]);
// Note that GB and GG share the country calling code 44, and that this number is possible but
// not valid.
NBPhoneNumber *possibleButInvalid = [[NBPhoneNumber alloc] init];
possibleButInvalid.countryCode = @44;
possibleButInvalid.nationalNumber = @11001;
XCTAssertTrue([util isPossibleShortNumber:possibleButInvalid]);
}
- (void)testIsValidShortNumber {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
NBPhoneNumber *valid = [[NBPhoneNumber alloc] init];
valid.countryCode = @33;
valid.nationalNumber = @1010;
XCTAssertTrue([util isValidShortNumber:valid]);
NBPhoneNumber *validWithRegion = [util parse:@"1010" defaultRegion:@"FR" error:nil];
XCTAssertNotNil(validWithRegion);
XCTAssertTrue([util isValidShortNumber:validWithRegion forRegion:@"FR"]);
NBPhoneNumber *invalid = [[NBPhoneNumber alloc] init];
invalid.countryCode = @33;
invalid.nationalNumber = @123456;
XCTAssertFalse([util isValidShortNumber:invalid]);
NBPhoneNumber *invalidWithRegion = [util parse:@"123456" defaultRegion:@"FR" error:nil];
XCTAssertNotNil(invalidWithRegion);
XCTAssertFalse([util isValidShortNumber:invalidWithRegion forRegion:@"FR"]);
// Note that GB and GG share the country calling code 44.
NBPhoneNumber *valid2 = [[NBPhoneNumber alloc] init];
valid2.countryCode = @44;
valid2.nationalNumber = @18001;
XCTAssertTrue([util isValidShortNumber:valid2]);
}
- (void)testIsCarrierSpecific {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
NBPhoneNumber *carrierSpecificNumber = [[NBPhoneNumber alloc] init];
carrierSpecificNumber.countryCode = @1;
carrierSpecificNumber.nationalNumber = @33669;
XCTAssertTrue([util isPhoneNumberCarrierSpecific:carrierSpecificNumber]);
// TODO(paween): Fix this -- should be 33669
XCTAssertTrue([util isPhoneNumberCarrierSpecific:[util parse:@"33669"
defaultRegion:@"US"
error:nil] forRegion:@"US"]);
NBPhoneNumber *notCarrierSpecific = [[NBPhoneNumber alloc] init];
notCarrierSpecific.countryCode = @1;
notCarrierSpecific.nationalNumber = @911;
XCTAssertFalse([util isPhoneNumberCarrierSpecific:notCarrierSpecific]);
XCTAssertFalse([util isPhoneNumberCarrierSpecific:[util parse:@"911"
defaultRegion:@"US"
error:nil] forRegion:@"US"]);
NBPhoneNumber *carrierSpecificForSomeRegion = [[NBPhoneNumber alloc] init];
carrierSpecificForSomeRegion.countryCode = @1;
carrierSpecificForSomeRegion.nationalNumber = @211;
XCTAssertTrue([util isPhoneNumberCarrierSpecific:carrierSpecificForSomeRegion]);
XCTAssertTrue([util isPhoneNumberCarrierSpecific:carrierSpecificForSomeRegion forRegion:@"US"]);
XCTAssertFalse([util isPhoneNumberCarrierSpecific:carrierSpecificForSomeRegion forRegion:@"BB"]);
}
- (void)testExpectedCost {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
// Premium rate.
NSString *premiumRateSample = [util exampleShortNumberForCost:NBEShortNumberCostPremiumRate
regionCode:@"FR"];
XCTAssertEqual(NBEShortNumberCostPremiumRate,
[util expectedCostOfPhoneNumber:[util parse:premiumRateSample defaultRegion:@"FR" error:nil]
forRegion:@"FR"]);
NBPhoneNumber *premiumRateNumber = [[NBPhoneNumber alloc] init];
premiumRateNumber.countryCode = @33;
premiumRateNumber.nationalNumber = @([premiumRateSample integerValue]);
XCTAssertEqual(NBEShortNumberCostPremiumRate,
[util expectedCostOfPhoneNumber:premiumRateNumber forRegion:@"FR"]);
// Standard rate.
NSString *standardRateSample = [util exampleShortNumberForCost:NBEShortNumberCostStandardRate
regionCode:@"FR"];
XCTAssertEqual(NBEShortNumberCostStandardRate,
[util expectedCostOfPhoneNumber:[util parse:standardRateSample defaultRegion:@"FR" error:nil]
forRegion:@"FR"]);
NBPhoneNumber *standardRateNumber = [[NBPhoneNumber alloc] init];
standardRateNumber.countryCode = @33;
standardRateNumber.nationalNumber = @([standardRateSample integerValue]);
XCTAssertEqual(NBEShortNumberCostStandardRate, [util expectedCostOfPhoneNumber:standardRateNumber
forRegion:@"FR"]);
// Toll free.
NSString *tollFreeSample = [util exampleShortNumberForCost:NBEShortNumberCostTollFree
regionCode:@"FR"];
XCTAssertEqual(NBEShortNumberCostTollFree,
[util expectedCostOfPhoneNumber:[util parse:tollFreeSample defaultRegion:@"FR" error:nil]
forRegion:@"FR"]);
NBPhoneNumber *tollFreeNumber = [[NBPhoneNumber alloc] init];
tollFreeNumber.countryCode = @33;
tollFreeNumber.nationalNumber = @([tollFreeSample integerValue]);
XCTAssertEqual(NBEShortNumberCostTollFree, [util expectedCostOfPhoneNumber:tollFreeNumber
forRegion:@"FR"]);
// Unknown cost.
XCTAssertEqual(NBEShortNumberCostUnknown,
[util expectedCostOfPhoneNumber:[util parse:@"12345" defaultRegion:@"FR" error:nil]
forRegion:@"FR"]);
NBPhoneNumber *unknownCostNumber = [[NBPhoneNumber alloc] init];
unknownCostNumber.countryCode = @33;
unknownCostNumber.nationalNumber = @12345;
XCTAssertEqual(NBEShortNumberCostUnknown, [util expectedCostOfPhoneNumber:unknownCostNumber
forRegion:@"FR"]);
// Test that an invalid number may nevertheless have a cost other than UNKNOWN_COST.
NBPhoneNumber *invalidShortNumber = [util parse:@"116123" defaultRegion:@"FR" error:nil];
XCTAssertFalse([util isValidShortNumber:invalidShortNumber forRegion:@"FR"]);
XCTAssertEqual(NBEShortNumberCostTollFree, [util expectedCostOfPhoneNumber:invalidShortNumber
forRegion:@"FR"]);
NBPhoneNumber *invalidShortNumber2 = [[NBPhoneNumber alloc] init];
invalidShortNumber2.countryCode = @33;
invalidShortNumber2.nationalNumber = @116123;
XCTAssertFalse([util isValidShortNumber:invalidShortNumber2 forRegion:@"FR"]);
XCTAssertEqual(NBEShortNumberCostTollFree, [util expectedCostOfPhoneNumber:invalidShortNumber2
forRegion:@"FR"]);
// Test a nonexistent country code.
NBPhoneNumber *usNumber = [util parse:@"911" defaultRegion:@"US" error:nil];
XCTAssertEqual(NBEShortNumberCostUnknown, [util expectedCostOfPhoneNumber:usNumber
forRegion:@"ZZ"]);
NBPhoneNumber *unknownNumber2 = [[NBPhoneNumber alloc] init];
unknownNumber2.countryCode = @123;
unknownNumber2.nationalNumber = @911;
XCTAssertEqual(NBEShortNumberCostUnknown, [util expectedCostOfPhoneNumber:unknownNumber2]);
}
- (void)testExpectedCostForSharedCountryCallingCode {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
NSString *ambiguousPremiumRateString = @"1234";
NBPhoneNumber *ambiguousPremiumRateNumber = [[NBPhoneNumber alloc] init];
ambiguousPremiumRateNumber.countryCode = @61;
ambiguousPremiumRateNumber.nationalNumber = @1234;
NSString *ambiguousStandardRateString = @"1194";
NBPhoneNumber *ambiguousStandardRateNumber = [[NBPhoneNumber alloc] init];
ambiguousStandardRateNumber.countryCode = @61;
ambiguousStandardRateNumber.nationalNumber = @1194;
NSString *ambiguousTollFreeString = @"733";
NBPhoneNumber *ambiguousTollFreeNumber = [[NBPhoneNumber alloc] init];
ambiguousTollFreeNumber.countryCode = @61;
ambiguousTollFreeNumber.nationalNumber = @733;
XCTAssertTrue([util isValidShortNumber:ambiguousPremiumRateNumber]);
XCTAssertTrue([util isValidShortNumber:ambiguousStandardRateNumber]);
XCTAssertTrue([util isValidShortNumber:ambiguousTollFreeNumber]);
XCTAssertTrue([util isValidShortNumber:[util parse:ambiguousPremiumRateString
defaultRegion:@"AU"
error:nil] forRegion:@"AU"]);
XCTAssertEqual(NBEShortNumberCostPremiumRate,
[util expectedCostOfPhoneNumber:[util parse:ambiguousPremiumRateString
defaultRegion:@"AU"
error:nil] forRegion:@"AU"]);
XCTAssertFalse([util isValidShortNumber:[util parse:ambiguousPremiumRateString
defaultRegion:@"CX"
error:nil] forRegion:@"CX"]);
XCTAssertEqual(NBEShortNumberCostUnknown,
[util expectedCostOfPhoneNumber:[util parse:ambiguousPremiumRateString
defaultRegion:@"CX"
error:nil] forRegion:@"CX"]);
// PREMIUM_RATE takes precedence over UNKNOWN_COST.
XCTAssertEqual(NBEShortNumberCostPremiumRate,
[util expectedCostOfPhoneNumber:ambiguousPremiumRateNumber]);
XCTAssertTrue([util isValidShortNumber:[util parse:ambiguousStandardRateString
defaultRegion:@"AU"
error:nil] forRegion:@"AU"]);
XCTAssertEqual(NBEShortNumberCostStandardRate,
[util expectedCostOfPhoneNumber:[util parse:ambiguousStandardRateString
defaultRegion:@"AU"
error:nil] forRegion:@"AU"]);
XCTAssertFalse([util isValidShortNumber:[util parse:ambiguousStandardRateString
defaultRegion:@"CX"
error:nil] forRegion:@"CX"]);
XCTAssertEqual(NBEShortNumberCostUnknown,
[util expectedCostOfPhoneNumber:[util parse:ambiguousStandardRateString
defaultRegion:@"CX"
error:nil] forRegion:@"CX"]);
XCTAssertEqual(NBEShortNumberCostUnknown,
[util expectedCostOfPhoneNumber:ambiguousStandardRateNumber]);
XCTAssertTrue([util isValidShortNumber:[util parse:ambiguousTollFreeString
defaultRegion:@"AU"
error:nil] forRegion:@"AU"]);
XCTAssertEqual(NBEShortNumberCostTollFree,
[util expectedCostOfPhoneNumber:[util parse:ambiguousTollFreeString
defaultRegion:@"AU"
error:nil] forRegion:@"AU"]);
XCTAssertFalse([util isValidShortNumber:[util parse:ambiguousTollFreeString
defaultRegion:@"CX"
error:nil] forRegion:@"CX"]);
XCTAssertEqual(NBEShortNumberCostUnknown,
[util expectedCostOfPhoneNumber:[util parse:ambiguousTollFreeString
defaultRegion:@"CX"
error:nil] forRegion:@"CX"]);
XCTAssertEqual(NBEShortNumberCostUnknown,
[util expectedCostOfPhoneNumber:ambiguousTollFreeNumber]);
}
- (void)testGetExampleShortNumber {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
XCTAssertEqualObjects(@"8711", [util exampleShortNumberWithRegionCode:@"AM"]);
XCTAssertEqualObjects(@"1010", [util exampleShortNumberWithRegionCode:@"FR"]);
XCTAssertEqualObjects(@"", [util exampleShortNumberWithRegionCode:@"UN001"]);
}
- (void)testGetExampleShortNumberForCost {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
XCTAssertEqualObjects(@"3010", [util exampleShortNumberForCost:NBEShortNumberCostTollFree
regionCode:@"FR"]);
XCTAssertEqualObjects(@"1023", [util exampleShortNumberForCost:NBEShortNumberCostStandardRate
regionCode:@"FR"]);
XCTAssertEqualObjects(@"42000", [util exampleShortNumberForCost:NBEShortNumberCostPremiumRate
regionCode:@"FR"]);
XCTAssertEqualObjects(@"", [util exampleShortNumberForCost:NBEShortNumberCostUnknown
regionCode:@"FR"]);
}
- (void)testConnectsToEmergencyNumber_US {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
XCTAssertTrue([util connectsToEmergencyNumberFromString:@"911" forRegion:@"US"]);
XCTAssertTrue([util connectsToEmergencyNumberFromString:@"112" forRegion:@"US"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"999" forRegion:@"US"]);
}
- (void)testConnectsToEmergencyNumberLongNumber_US {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
XCTAssertTrue([util connectsToEmergencyNumberFromString:@"9116666666" forRegion:@"US"]);
XCTAssertTrue([util connectsToEmergencyNumberFromString:@"1126666666" forRegion:@"US"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"9996666666" forRegion:@"US"]);
}
- (void)testConnectsToEmergencyNumberWithFormatting_US {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
XCTAssertTrue([util connectsToEmergencyNumberFromString:@"9-1-1" forRegion:@"US"]);
XCTAssertTrue([util connectsToEmergencyNumberFromString:@"1-1-2" forRegion:@"US"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"9-9-9" forRegion:@"US"]);
}
- (void)testConnectsToEmergencyNumberWithPlusSign_US {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"+911" forRegion:@"US"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"\uFF0B911" forRegion:@"US"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@" +911" forRegion:@"US"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"+112" forRegion:@"US"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"+999" forRegion:@"US"]);
}
- (void)testConnectsToEmergencyNumber_BR {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
XCTAssertTrue([util connectsToEmergencyNumberFromString:@"911" forRegion:@"BR"]);
XCTAssertTrue([util connectsToEmergencyNumberFromString:@"190" forRegion:@"BR"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"999" forRegion:@"BR"]);
}
- (void)testConnectsToEmergencyNumberLongNumber_BR {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
// Brazilian emergency numbers don't work when additional digits are appended.
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"9111" forRegion:@"BR"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"1900" forRegion:@"BR"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"9996" forRegion:@"BR"]);
}
- (void)testConnectsToEmergencyNumber_CL {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
XCTAssertTrue([util connectsToEmergencyNumberFromString:@"131" forRegion:@"CL"]);
XCTAssertTrue([util connectsToEmergencyNumberFromString:@"133" forRegion:@"CL"]);
}
- (void)testConnectsToEmergencyNumberLongNumber_CL {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
// Chilean emergency numbers don't work when additional digits are appended.
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"1313" forRegion:@"CL"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"1330" forRegion:@"CL"]);
}
- (void)testConnectsToEmergencyNumber_AO {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
// Angola doesn't have any metadata for emergency numbers.
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"911" forRegion:@"AO"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"222123456" forRegion:@"AO"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"923123456" forRegion:@"AO"]);
}
- (void)testConnectsToEmergencyNumber_ZW {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
// Zimbabwe doesn't have any metadata.
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"911" forRegion:@"ZW"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"01312345" forRegion:@"ZW"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"0711234567" forRegion:@"ZW"]);
}
- (void)testIsEmergencyNumber_US {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
XCTAssertTrue([util isEmergencyNumber:@"911" forRegion:@"US"]);
XCTAssertTrue([util isEmergencyNumber:@"112" forRegion:@"US"]);
XCTAssertFalse([util isEmergencyNumber:@"999" forRegion:@"US"]);
}
- (void)testIsEmergencyNumberLongNumber_US {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
XCTAssertFalse([util isEmergencyNumber:@"9116666666" forRegion:@"US"]);
XCTAssertFalse([util isEmergencyNumber:@"1126666666" forRegion:@"US"]);
XCTAssertFalse([util isEmergencyNumber:@"9996666666" forRegion:@"US"]);
}
- (void)testIsEmergencyNumberWithFormatting_US {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
XCTAssertTrue([util isEmergencyNumber:@"9-1-1" forRegion:@"US"]);
XCTAssertTrue([util isEmergencyNumber:@"*911" forRegion:@"US"]);
XCTAssertTrue([util isEmergencyNumber:@"1-1-2" forRegion:@"US"]);
XCTAssertTrue([util isEmergencyNumber:@"*112" forRegion:@"US"]);
XCTAssertFalse([util isEmergencyNumber:@"9-9-9" forRegion:@"US"]);
XCTAssertFalse([util isEmergencyNumber:@"*999" forRegion:@"US"]);
}
- (void)testIsEmergencyNumberWithPlusSign_US {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
XCTAssertFalse([util isEmergencyNumber:@"+911" forRegion:@"US"]);
XCTAssertFalse([util isEmergencyNumber:@"\uFF0B911" forRegion:@"US"]);
XCTAssertFalse([util isEmergencyNumber:@" +911" forRegion:@"US"]);
XCTAssertFalse([util isEmergencyNumber:@"+112" forRegion:@"US"]);
XCTAssertFalse([util isEmergencyNumber:@"+999" forRegion:@"US"]);
}
- (void)testIsEmergencyNumber_BR {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
XCTAssertTrue([util connectsToEmergencyNumberFromString:@"911" forRegion:@"BR"]);
XCTAssertTrue([util connectsToEmergencyNumberFromString:@"190" forRegion:@"BR"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"999" forRegion:@"BR"]);
}
- (void)testIsEmergencyNumberLongNumber_BR {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
// Brazilian emergency numbers don't work when additional digits are appended.
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"9111" forRegion:@"BR"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"1900" forRegion:@"BR"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"9996" forRegion:@"BR"]);
}
- (void)testIsEmergencyNumber_AO {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
// Angola doesn't have any metadata for emergency numbers.
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"911" forRegion:@"AO"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"222123456" forRegion:@"AO"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"923123456" forRegion:@"AO"]);
}
- (void)testIsEmergencyNumber_ZW {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
// Zimbabwe doesn't have any metadata.
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"911" forRegion:@"ZW"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"01312345" forRegion:@"ZW"]);
XCTAssertFalse([util connectsToEmergencyNumberFromString:@"0711234567" forRegion:@"ZW"]);
}
- (void)testEmergencyNumberForSharedCountryCallingCode {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
// Test the emergency number 112, which is valid in both Australia and the Christmas Islands.
NBPhoneNumber *auEmergencyNumber = [util parse:@"112" defaultRegion:@"AU" error:nil];
XCTAssertTrue([util isEmergencyNumber:@"112" forRegion:@"AU"]);
XCTAssertTrue([util isValidShortNumber:auEmergencyNumber forRegion:@"AU"]);
XCTAssertEqual(NBEShortNumberCostTollFree,
[util expectedCostOfPhoneNumber:auEmergencyNumber forRegion:@"AU"]);
XCTAssertTrue([util isEmergencyNumber:@"112" forRegion:@"CX"]);
XCTAssertTrue([util isValidShortNumber:auEmergencyNumber forRegion:@"CX"]);
XCTAssertEqual(NBEShortNumberCostTollFree,
[util expectedCostOfPhoneNumber:auEmergencyNumber forRegion:@"CX"]);
NBPhoneNumber *sharedEmergencyNumber = [[NBPhoneNumber alloc] init];
sharedEmergencyNumber.countryCode = @61;
sharedEmergencyNumber.nationalNumber = @112;
XCTAssertTrue([util isValidShortNumber:sharedEmergencyNumber]);
XCTAssertEqual(NBEShortNumberCostTollFree,
[util expectedCostOfPhoneNumber:sharedEmergencyNumber]);
}
- (void)testOverlappingNANPANumber {
// 211 is an emergency number in Barbados, while it is a toll-free information line in Canada
// and the USA.
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
NBPhoneNumber *bb211 = [util parse:@"211" defaultRegion:@"BB" error:nil];
NBPhoneNumber *us211 = [util parse:@"211" defaultRegion:@"US" error:nil];
NBPhoneNumber *ca211 = [util parse:@"211" defaultRegion:@"CA" error:nil];
XCTAssertTrue([util isEmergencyNumber:@"211" forRegion:@"BB"]);
XCTAssertEqual(NBEShortNumberCostTollFree,
[util expectedCostOfPhoneNumber:bb211 forRegion:@"BB"]);
XCTAssertFalse([util isEmergencyNumber:@"211" forRegion:@"US"]);
XCTAssertEqual(NBEShortNumberCostUnknown,
[util expectedCostOfPhoneNumber:us211 forRegion:@"US"]);
XCTAssertFalse([util isEmergencyNumber:@"211" forRegion:@"CA"]);
XCTAssertEqual(NBEShortNumberCostTollFree,
[util expectedCostOfPhoneNumber:ca211 forRegion:@"CA"]);
}
- (void)testCountryCallingCodeIsNotIgnored {
NBPhoneNumberUtil *util = [[NBPhoneNumberUtil alloc] init];
// +46 is the country calling code for Sweden (SE), and 40404 is a valid short number in the US.
NBPhoneNumber *seNumber = [util parse:@"+4640404" defaultRegion:@"SE" error:nil];
XCTAssertFalse([util isPossibleShortNumber:seNumber forRegion:@"US"]);
XCTAssertFalse([util isValidShortNumber:seNumber forRegion:@"US"]);
XCTAssertEqual(NBEShortNumberCostUnknown,
[util expectedCostOfPhoneNumber:seNumber forRegion:@"US"]);
}
@end
#endif // SHORT_NUMBER_SUPPORT

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

53
libPhoneNumberTests/index.php Executable file
View File

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html>
<?PHP
$mode = isset($_REQUEST['test']) ? true:false;
$metadataSrc = "http://libphonenumber.googlecode.com/svn/trunk/javascript/i18n/phonenumbers/metadata.js";
$fileName = "PhoneNumberMetaData";
if ($mode)
{
$metadataSrc = "http://libphonenumber.googlecode.com/svn/trunk/javascript/i18n/phonenumbers/metadatafortesting.js";
$fileName = "PhoneNumberMetaDataForTesting";
}
?>
<head>
<title>libPhoneNumber for iOS metadata generator</title>
<script src="http://cdn.rawgit.com/google/closure-library/master/closure/goog/base.js"></script>
<script>
goog.require('goog.proto2.Message');
goog.require('goog.dom');
goog.require('goog.json');
goog.require('goog.array');
goog.require('goog.proto2.ObjectSerializer');
goog.require('goog.string.StringBuffer');
</script>
<script src="http://libphonenumber.googlecode.com/svn/trunk/javascript/i18n/phonenumbers/phonemetadata.pb.js"></script>
<script src="http://libphonenumber.googlecode.com/svn/trunk/javascript/i18n/phonenumbers/phonenumber.pb.js"></script>
<script src=<?PHP echo '"'.$metadataSrc.'"'; ?>></script>
<script src="http://libphonenumber.googlecode.com/svn/trunk/javascript/i18n/phonenumbers/phonenumberutil.js"></script>
<script src="http://libphonenumber.googlecode.com/svn/trunk/javascript/i18n/phonenumbers/asyoutypeformatter.js"></script>
<script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
<script>
goog.require('i18n.phonenumbers.metadata');
$(document).ready(function () {
var goodDomElement = goog.dom.getElement;
var jsonData = encodeURIComponent(JSON.stringify(i18n.phonenumbers.metadata));
$.ajax({
type: "POST",
url: "libPhoneNumberGenerator.php",
data: { jsonData: jsonData, fileName: <?php echo '"'.$fileName.'"'; ?> }
}).done(function(msg) {
$('#console').html(""+msg);
});
});
</script>
</head>
<body>
<div id="console">Generate libPhoneNumber metadata for iOS</div>
</body>
</html>

View File

@ -0,0 +1,15 @@
<?PHP
$str = urldecode($_REQUEST['jsonData']);
$name = $_REQUEST['fileName'];
if ($str && $name)
{
$fp = fopen('./generatedJSON/'.$name.'.json', 'w');
fwrite($fp, $str);
fclose($fp);
echo "complete generate : ".$name;
exit;
}
echo "error";
?>

View File

@ -0,0 +1,142 @@
#!/usr/bin/swift
//
// metadataGenerator.swift
// libPhoneNumber-iOS
//
// Created by Paween Itthipalkul on 2/16/18.
// Copyright © 2018 Google LLC. All rights reserved.
//
import Darwin
import Foundation
import JavaScriptCore
enum GeneratorError: Error {
case dataNotString
case genericError
}
func synchronouslyLoadStringResource(from url: URL) throws -> String {
let session = URLSession(configuration: .default)
var resultData: Data?
var resultError: Error?
let semaphore = DispatchSemaphore(value: 0)
let dataTask = session.dataTask(with: url) { data, _, error in
resultData = data
resultError = error
semaphore.signal()
}
dataTask.resume()
semaphore.wait()
if let error = resultError {
throw error
}
if let data = resultData {
guard let string = String(data: data, encoding: .utf8) else {
throw GeneratorError.dataNotString
}
return string
}
throw GeneratorError.genericError
}
func loadJS(from url: URL, to context: JSContext) {
guard let script = try? synchronouslyLoadStringResource(from: url) else {
fputs("Cannot load dependency at \(url)\n", __stderrp)
exit(1)
}
context.evaluateScript(script)
}
// Create JavaScript context.
let context = JSContext()!
context.exceptionHandler = { _, exception in
fputs("Javascript exception thrown: \(exception!)\n", __stderrp)
// exit(1)
}
// Load required dependencies.
let googleClosure = URL(
string: "http://cdn.rawgit.com/google/closure-library/master/closure/goog/base.js")!
loadJS(from: googleClosure, to: context)
let jQuery = URL(string: "http://code.jquery.com/jquery-1.8.3.min.js")!
loadJS(from: jQuery, to: context)
// Evaluate requires.
let requires = """
goog.require('goog.proto2.Message');
goog.require('goog.dom');
goog.require('goog.json');
goog.require('goog.array');
goog.require('goog.proto2.ObjectSerializer');
goog.require('goog.string.StringBuffer');
goog.require('i18n.phonenumbers.metadata');
"""
context.evaluateScript(requires)
// Load metadata file from GitHub.
let phoneMetadata = URL(string: "https://raw.githubusercontent.com/googlei18n/libphonenumber/master/javascript/i18n/phonenumbers/metadata.js")!
let phoneMetadataForTesting = URL(string: "https://raw.githubusercontent.com/googlei18n/libphonenumber/master/javascript/i18n/phonenumbers/metadatafortesting.js")!
let shortNumberMetadata = URL(string: "https://raw.githubusercontent.com/googlei18n/libphonenumber/master/javascript/i18n/phonenumbers/shortnumbermetadata.js")!
let currentDir = FileManager.default.currentDirectoryPath
let baseURL = URL(fileURLWithPath: currentDir).appendingPathComponent("generatedJSON")
// Phone metadata.
do {
let metadata = try synchronouslyLoadStringResource(from: phoneMetadata)
context.evaluateScript(metadata)
let result = context.evaluateScript("JSON.stringify(i18n.phonenumbers.metadata)")!.toString()!
let url = baseURL.appendingPathComponent("PhoneNumberMetaData.json")
try result.write(
to: url,
atomically: true,
encoding: .utf8)
// Clean up
context.evaluateScript("i18n.phonenumbers.metadata = null")
} catch (let error) {
fputs("Error loading phone number metadata \(error)\n", __stderrp)
exit(1)
}
// Phone metadata for testing.
do {
let metadata = try synchronouslyLoadStringResource(from: phoneMetadataForTesting)
context.evaluateScript(metadata)
let result = context.evaluateScript("JSON.stringify(i18n.phonenumbers.metadata)")!.toString()!
let url = baseURL.appendingPathComponent("PhoneNumberMetaDataForTesting.json")
try result.write(
to: url,
atomically: true,
encoding: .utf8)
} catch (let error) {
fputs("Error loading phone number metadata for testing \(error)\n", __stderrp)
exit(1)
}
// Short number metadata.
do {
let metadata = try synchronouslyLoadStringResource(from: shortNumberMetadata)
context.evaluateScript(metadata)
let result = context.evaluateScript(
"JSON.stringify(i18n.phonenumbers.shortnumbermetadata)")!.toString()!
let url = baseURL.appendingPathComponent("ShortNumberMetadata.json")
try result.write(
to: url,
atomically: true,
encoding: .utf8)
} catch (let error) {
fputs("Error loading short number metadata \(error)\n", __stderrp)
exit(1)
}
print("Done")

2
spec_helper.rb Normal file
View File

@ -0,0 +1,2 @@
require 'coveralls'
Coveralls.wear!