// // NBMetadataHelper.m // libPhoneNumber // // Created by tabby on 2015. 2. 8.. // Copyright (c) 2015년 ohtalk.me. All rights reserved. // #import "NBMetadataHelper.h" #import "NBPhoneMetaData.h" #import "NBMetadataCore.h" #if TESTING==1 #define NB_CLASS_PREFIX @"NBPhoneMetadataTest" #import "NBMetadataCoreTest.h" #import "NBMetadataCoreTestMapper.h" #else #define NB_CLASS_PREFIX @"NBPhoneMetadata" #import "NBMetadataCore.h" #import "NBMetadataCoreMapper.h" #endif @interface NBMetadataHelper () // Cached metadata @property(nonatomic, strong) NBPhoneMetaData *cachedMetaData; @property(nonatomic, strong) NSString *cachedMetaDataKey; @end @implementation NBMetadataHelper /* Terminologies - Country Number (CN) = Country code for i18n calling - Country Code (CC) : ISO country codes (2 chars) Ref. site (countrycode.org) */ static NSMutableDictionary *kMapCCode2CN = nil; /** * initialization meta-meta variables */ - (void)initializeHelper { if (!NBPhoneMetadataAM.class) // force linkage of NBMetadataCore.m return; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ kMapCCode2CN = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"1", @"US", @"1", @"AG", @"1", @"AI", @"1", @"AS", @"1", @"BB", @"1", @"BM", @"1", @"BS", @"1", @"CA", @"1", @"DM", @"1", @"DO", @"1", @"GD", @"1", @"GU", @"1", @"JM", @"1", @"KN", @"1", @"KY", @"1", @"LC", @"1", @"MP", @"1", @"MS", @"1", @"PR", @"1", @"SX", @"1", @"TC", @"1", @"TT", @"1", @"VC", @"1", @"VG", @"1", @"VI", @"7", @"RU", @"7", @"KZ", @"20", @"EG", @"27", @"ZA", @"30", @"GR", @"31", @"NL", @"32", @"BE", @"33", @"FR", @"34", @"ES", @"36", @"HU", @"39", @"IT", @"40", @"RO", @"41", @"CH", @"43", @"AT", @"44", @"GB", @"44", @"GG", @"44", @"IM", @"44", @"JE", @"45", @"DK", @"46", @"SE", @"47", @"NO", @"47", @"SJ", @"48", @"PL", @"49", @"DE", @"51", @"PE", @"52", @"MX", @"53", @"CU", @"54", @"AR", @"55", @"BR", @"56", @"CL", @"57", @"CO", @"58", @"VE", @"60", @"MY", @"61", @"AU", @"61", @"CC", @"61", @"CX", @"62", @"ID", @"63", @"PH", @"64", @"NZ", @"65", @"SG", @"66", @"TH", @"81", @"JP", @"82", @"KR", @"84", @"VN", @"86", @"CN", @"90", @"TR", @"91", @"IN", @"92", @"PK", @"93", @"AF", @"94", @"LK", @"95", @"MM", @"98", @"IR", @"211", @"SS", @"212", @"MA", @"212", @"EH", @"213", @"DZ", @"216", @"TN", @"218", @"LY", @"220", @"GM", @"221", @"SN", @"222", @"MR", @"223", @"ML", @"224", @"GN", @"225", @"CI", @"226", @"BF", @"227", @"NE", @"228", @"TG", @"229", @"BJ", @"230", @"MU", @"231", @"LR", @"232", @"SL", @"233", @"GH", @"234", @"NG", @"235", @"TD", @"236", @"CF", @"237", @"CM", @"238", @"CV", @"239", @"ST", @"240", @"GQ", @"241", @"GA", @"242", @"CG", @"243", @"CD", @"244", @"AO", @"245", @"GW", @"246", @"IO", @"247", @"AC", @"248", @"SC", @"249", @"SD", @"250", @"RW", @"251", @"ET", @"252", @"SO", @"253", @"DJ", @"254", @"KE", @"255", @"TZ", @"256", @"UG", @"257", @"BI", @"258", @"MZ", @"260", @"ZM", @"261", @"MG", @"262", @"RE", @"262", @"YT", @"263", @"ZW", @"264", @"NA", @"265", @"MW", @"266", @"LS", @"267", @"BW", @"268", @"SZ", @"269", @"KM", @"290", @"SH", @"291", @"ER", @"297", @"AW", @"298", @"FO", @"299", @"GL", @"350", @"GI", @"351", @"PT", @"352", @"LU", @"353", @"IE", @"354", @"IS", @"355", @"AL", @"356", @"MT", @"357", @"CY", @"358", @"FI",@"358", @"AX", @"359", @"BG", @"370", @"LT", @"371", @"LV", @"372", @"EE", @"373", @"MD", @"374", @"AM", @"375", @"BY", @"376", @"AD", @"377", @"MC", @"378", @"SM", @"379", @"VA", @"380", @"UA", @"381", @"RS", @"382", @"ME", @"385", @"HR", @"386", @"SI", @"387", @"BA", @"389", @"MK", @"420", @"CZ", @"421", @"SK", @"423", @"LI", @"500", @"FK", @"501", @"BZ", @"502", @"GT", @"503", @"SV", @"504", @"HN", @"505", @"NI", @"506", @"CR", @"507", @"PA", @"508", @"PM", @"509", @"HT", @"590", @"GP", @"590", @"BL", @"590", @"MF", @"591", @"BO", @"592", @"GY", @"593", @"EC", @"594", @"GF", @"595", @"PY", @"596", @"MQ", @"597", @"SR", @"598", @"UY", @"599", @"CW", @"599", @"BQ", @"670", @"TL", @"672", @"NF", @"673", @"BN", @"674", @"NR", @"675", @"PG", @"676", @"TO", @"677", @"SB", @"678", @"VU", @"679", @"FJ", @"680", @"PW", @"681", @"WF", @"682", @"CK", @"683", @"NU", @"685", @"WS", @"686", @"KI", @"687", @"NC", @"688", @"TV", @"689", @"PF", @"690", @"TK", @"691", @"FM", @"692", @"MH", @"800", @"001", @"808", @"001", @"850", @"KP", @"852", @"HK", @"853", @"MO", @"855", @"KH", @"856", @"LA", @"870", @"001", @"878", @"001", @"880", @"BD", @"881", @"001", @"882", @"001", @"883", @"001", @"886", @"TW", @"888", @"001", @"960", @"MV", @"961", @"LB", @"962", @"JO", @"963", @"SY", @"964", @"IQ", @"965", @"KW", @"966", @"SA", @"967", @"YE", @"968", @"OM", @"970", @"PS", @"971", @"AE", @"972", @"IL", @"973", @"BH", @"974", @"QA", @"975", @"BT", @"976", @"MN", @"977", @"NP", @"979", @"001", @"992", @"TJ", @"993", @"TM", @"994", @"AZ", @"995", @"GE", @"996", @"KG", @"998", @"UZ", nil]; }); } - (NSDictionary *)CCode2CNMap{ if (!kMapCCode2CN){ [self initializeHelper]; } return kMapCCode2CN; } - (void)clearHelper { if (kMapCCode2CN) { [kMapCCode2CN removeAllObjects]; kMapCCode2CN = nil; } } - (NSArray*)getAllMetadata { NSArray *countryCodes = [NSLocale ISOCountryCodes]; NSMutableArray *resultMetadata = [[NSMutableArray alloc] init]; for (NSString *countryCode in countryCodes) { id countryDictionaryInstance = [NSDictionary dictionaryWithObject:countryCode forKey:NSLocaleCountryCode]; NSString *identifier = [NSLocale localeIdentifierFromComponents:countryDictionaryInstance]; NSString *country = [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:identifier]; NSMutableDictionary *countryMeta = [[NSMutableDictionary alloc] init]; if (country) { [countryMeta setObject:country forKey:@"name"]; } if (countryCode) { [countryMeta setObject:countryCode forKey:@"code"]; } NBPhoneMetaData *metaData = [self getMetadataForRegion:countryCode]; if (metaData) { [countryMeta setObject:metaData forKey:@"metadata"]; } [resultMetadata addObject:countryMeta]; } return resultMetadata; } - (NSArray *)regionCodeFromCountryCode:(NSNumber *)countryCodeNumber { [self initializeHelper]; id res = nil; #if TESTING==1 res = [NBMetadataCoreTestMapper ISOCodeFromCallingNumber:[countryCodeNumber stringValue]]; #else res = [NBMetadataCoreMapper ISOCodeFromCallingNumber:[countryCodeNumber stringValue]]; #endif if (res && [res isKindOfClass:[NSArray class]] && [((NSArray*)res) count] > 0) { return res; } return nil; } - (NSString *)countryCodeFromRegionCode:(NSString* )regionCode { [self initializeHelper]; id res = [kMapCCode2CN objectForKey:regionCode]; if (res) { return res; } return nil; } - (NSString *)stringByTrimming:(NSString *)aString { if (aString == nil || aString.length <= 0) return aString; aString = [self normalizeNonBreakingSpace:aString]; NSString *aRes = @""; NSArray *newlines = [aString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; for (NSString *line in newlines) { NSString *performedString = [line stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; if (performedString.length > 0) { aRes = [aRes stringByAppendingString:performedString]; } } if (newlines.count <= 0) { return aString; } return aRes; } - (NSString *)normalizeNonBreakingSpace:(NSString *)aString { return [aString stringByReplacingOccurrencesOfString:NB_NON_BREAKING_SPACE withString:@" "]; } /** * Returns the metadata for the given region code or {@code nil} if the region * code is invalid or unknown. * * @param {?string} regionCode * @return {i18n.phonenumbers.PhoneMetadata} */ - (NBPhoneMetaData *)getMetadataForRegion:(NSString *)regionCode { [self initializeHelper]; if ([NBMetadataHelper hasValue:regionCode] == NO) { return nil; } regionCode = [regionCode uppercaseString]; if (_cachedMetaDataKey && [_cachedMetaDataKey isEqualToString:regionCode]) { return _cachedMetaData; } NSString *className = [NSString stringWithFormat:@"%@%@", NB_CLASS_PREFIX, regionCode]; Class metaClass = NSClassFromString(className); if (metaClass) { NBPhoneMetaData *metadata = [[metaClass alloc] init]; _cachedMetaData = metadata; _cachedMetaDataKey = regionCode; return metadata; } return nil; } /** * @param {number} countryCallingCode * @return {i18n.phonenumbers.PhoneMetadata} */ - (NBPhoneMetaData *)getMetadataForNonGeographicalRegion:(NSNumber *)countryCallingCode { NSString *countryCallingCodeStr = [NSString stringWithFormat:@"%@", countryCallingCode]; return [self getMetadataForRegion:countryCallingCodeStr]; } #pragma mark - Regular expression Utilities - + (BOOL)hasValue:(NSString*)string { static dispatch_once_t onceToken; static NSCharacterSet *whitespaceCharSet = nil; dispatch_once(&onceToken, ^{ NSMutableCharacterSet *spaceCharSet = [NSMutableCharacterSet characterSetWithCharactersInString:NB_NON_BREAKING_SPACE]; [spaceCharSet formUnionWithCharacterSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; whitespaceCharSet = spaceCharSet; }); if (string == nil || [string stringByTrimmingCharactersInSet:whitespaceCharSet].length <= 0) { return NO; } return YES; } @end