mirror of https://github.com/NekoX-Dev/NekoX.git
366 lines
13 KiB
Java
366 lines
13 KiB
Java
// Copyright (c) 2012, Rick Maddy
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright notice, this
|
|
// list of conditions and the following disclaimer.
|
|
//
|
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
// and/or other materials provided with the distribution.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
package org.telegram.PhoneFormat;
|
|
|
|
import org.telegram.messenger.Utilities;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.InputStream;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.Locale;
|
|
|
|
public class PhoneFormat {
|
|
public byte[] data;
|
|
public ByteBuffer buffer;
|
|
public String defaultCountry;
|
|
public String defaultCallingCode;
|
|
public HashMap<String, Integer> callingCodeOffsets;
|
|
public HashMap<String, ArrayList<String>> callingCodeCountries;
|
|
public HashMap<String, CallingCodeInfo> callingCodeData;
|
|
public HashMap<String, String> countryCallingCode;
|
|
|
|
public static PhoneFormat Instance = new PhoneFormat();
|
|
|
|
public static String strip(String str) {
|
|
StringBuilder res = new StringBuilder(str);
|
|
String phoneChars = "0123456789+*#";
|
|
for (int i = res.length() - 1; i >= 0; i--) {
|
|
if (!phoneChars.contains(res.substring(i, i + 1))) {
|
|
res.deleteCharAt(i);
|
|
}
|
|
}
|
|
return res.toString();
|
|
}
|
|
|
|
public static String stripExceptNumbers(String str) {
|
|
StringBuilder res = new StringBuilder(str);
|
|
String phoneChars = "0123456789";
|
|
for (int i = res.length() - 1; i >= 0; i--) {
|
|
if (!phoneChars.contains(res.substring(i, i + 1))) {
|
|
res.deleteCharAt(i);
|
|
}
|
|
}
|
|
return res.toString();
|
|
}
|
|
|
|
public PhoneFormat() {
|
|
init(null);
|
|
}
|
|
|
|
public PhoneFormat(String countryCode) {
|
|
init(countryCode);
|
|
}
|
|
|
|
public void init(String countryCode) {
|
|
try {
|
|
InputStream stream = Utilities.applicationContext.getAssets().open("PhoneFormats.dat");
|
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
byte[] buf = new byte[1024];
|
|
int len;
|
|
while ((len = stream.read(buf, 0, 1024)) != -1) {
|
|
bos.write(buf, 0, len);
|
|
}
|
|
data = bos.toByteArray();
|
|
buffer = ByteBuffer.wrap(data);
|
|
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
|
|
if (countryCode != null && countryCode.length() != 0) {
|
|
defaultCountry = countryCode;
|
|
} else {
|
|
Locale loc = Locale.getDefault();
|
|
defaultCountry = loc.getCountry().toLowerCase();
|
|
}
|
|
callingCodeOffsets = new HashMap<String, Integer>(255);
|
|
callingCodeCountries = new HashMap<String, ArrayList<String>>(255);
|
|
callingCodeData = new HashMap<String, CallingCodeInfo>(10);
|
|
countryCallingCode = new HashMap<String, String>(255);
|
|
|
|
parseDataHeader();
|
|
}
|
|
|
|
public String defaultCallingCode() {
|
|
return callingCodeForCountryCode(defaultCountry);
|
|
}
|
|
|
|
public String callingCodeForCountryCode(String countryCode) {
|
|
return countryCallingCode.get(countryCode.toLowerCase());
|
|
}
|
|
|
|
public ArrayList countriesForCallingCode(String callingCode) {
|
|
if (callingCode.startsWith("+")) {
|
|
callingCode = callingCode.substring(1);
|
|
}
|
|
|
|
return callingCodeCountries.get(callingCode);
|
|
}
|
|
|
|
public CallingCodeInfo findCallingCodeInfo(String str) {
|
|
CallingCodeInfo res = null;
|
|
for (int i = 0; i < 3; i++) {
|
|
if (i < str.length()) {
|
|
res = callingCodeInfo(str.substring(0, i + 1));
|
|
if (res != null) {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
public String format(String orig) {
|
|
String str = strip(orig);
|
|
|
|
if (str.startsWith("+")) {
|
|
String rest = str.substring(1);
|
|
CallingCodeInfo info = findCallingCodeInfo(rest);
|
|
if (info != null) {
|
|
String phone = info.format(rest);
|
|
return "+" + phone;
|
|
} else {
|
|
return orig;
|
|
}
|
|
} else {
|
|
CallingCodeInfo info = callingCodeInfo(defaultCallingCode);
|
|
if (info == null) {
|
|
return orig;
|
|
}
|
|
|
|
String accessCode = info.matchingAccessCode(str);
|
|
if (accessCode != null) {
|
|
String rest = str.substring(accessCode.length());
|
|
String phone = rest;
|
|
CallingCodeInfo info2 = findCallingCodeInfo(rest);
|
|
if (info2 != null) {
|
|
phone = info2.format(rest);
|
|
}
|
|
|
|
if (phone.length() == 0) {
|
|
return accessCode;
|
|
} else {
|
|
return String.format("%s %s", accessCode, phone);
|
|
}
|
|
} else {
|
|
return info.format(str);
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean isPhoneNumberValid(String phoneNumber) {
|
|
String str = strip(phoneNumber);
|
|
|
|
if (str.startsWith("+")) {
|
|
String rest = str.substring(1);
|
|
CallingCodeInfo info = findCallingCodeInfo(rest);
|
|
return info != null && info.isValidPhoneNumber(rest);
|
|
} else {
|
|
CallingCodeInfo info = callingCodeInfo(defaultCallingCode);
|
|
if (info == null) {
|
|
return false;
|
|
}
|
|
|
|
String accessCode = info.matchingAccessCode(str);
|
|
if (accessCode != null) {
|
|
String rest = str.substring(accessCode.length());
|
|
if (rest.length() != 0) {
|
|
CallingCodeInfo info2 = findCallingCodeInfo(rest);
|
|
return info2 != null && info2.isValidPhoneNumber(rest);
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
return info.isValidPhoneNumber(str);
|
|
}
|
|
}
|
|
}
|
|
|
|
int value32(int offset) {
|
|
if (offset + 4 <= data.length) {
|
|
buffer.position(offset);
|
|
return buffer.getInt();
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
short value16(int offset) {
|
|
if (offset + 2 <= data.length) {
|
|
buffer.position(offset);
|
|
return buffer.getShort();
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public String valueString(int offset) {
|
|
try {
|
|
for (int a = offset; a < data.length; a++) {
|
|
if (data[a] == '\0') {
|
|
if (offset == a - offset) {
|
|
return "";
|
|
}
|
|
return new String(data, offset, a - offset);
|
|
}
|
|
}
|
|
return "";
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
return "";
|
|
}
|
|
}
|
|
|
|
public CallingCodeInfo callingCodeInfo(String callingCode) {
|
|
CallingCodeInfo res = callingCodeData.get(callingCode);
|
|
if (res == null) {
|
|
Integer num = callingCodeOffsets.get(callingCode);
|
|
if (num != null) {
|
|
final byte[] bytes = data;
|
|
int start = num;
|
|
int offset = start;
|
|
res = new CallingCodeInfo();
|
|
res.callingCode = callingCode;
|
|
res.countries = callingCodeCountries.get(callingCode);
|
|
callingCodeData.put(callingCode, res);
|
|
|
|
int block1Len = value16(offset);
|
|
offset += 2;
|
|
|
|
offset += 2;
|
|
int block2Len = value16(offset);
|
|
offset += 2;
|
|
|
|
offset += 2;
|
|
int setCnt = value16(offset);
|
|
offset += 2;
|
|
|
|
offset += 2;
|
|
|
|
ArrayList<String> strs = new ArrayList<String>(5);
|
|
String str;
|
|
while ((str = valueString(offset)).length() != 0) {
|
|
strs.add(str);
|
|
offset += str.length() + 1;
|
|
}
|
|
res.trunkPrefixes = strs;
|
|
offset++;
|
|
|
|
strs = new ArrayList<String>(5);
|
|
while ((str = valueString(offset)).length() != 0) {
|
|
strs.add(str);
|
|
offset += str.length() + 1;
|
|
}
|
|
res.intlPrefixes = strs;
|
|
|
|
ArrayList<RuleSet> ruleSets = new ArrayList<RuleSet>(setCnt);
|
|
offset = start + block1Len;
|
|
for (int s = 0; s < setCnt; s++) {
|
|
RuleSet ruleSet = new RuleSet();
|
|
ruleSet.matchLen = value16(offset);
|
|
offset += 2;
|
|
int ruleCnt = value16(offset);
|
|
offset += 2;
|
|
ArrayList<PhoneRule> rules = new ArrayList<PhoneRule>(ruleCnt);
|
|
for (int r = 0; r < ruleCnt; r++) {
|
|
PhoneRule rule = new PhoneRule();
|
|
rule.minVal = value32(offset);
|
|
offset += 4;
|
|
rule.maxVal = value32(offset);
|
|
offset += 4;
|
|
rule.byte8 = (int)bytes[offset++];
|
|
rule.maxLen = (int)bytes[offset++];
|
|
rule.otherFlag = (int)bytes[offset++];
|
|
rule.prefixLen = (int)bytes[offset++];
|
|
rule.flag12 = (int)bytes[offset++];
|
|
rule.flag13 = (int)bytes[offset++];
|
|
int strOffset = value16(offset);
|
|
offset += 2;
|
|
rule.format = valueString(start + block1Len + block2Len + strOffset);
|
|
|
|
int openPos = rule.format.indexOf("[[");
|
|
if (openPos != -1) {
|
|
int closePos = rule.format.indexOf("]]");
|
|
rule.format = String.format("%s%s", rule.format.substring(0, openPos), rule.format.substring(closePos + 2));
|
|
}
|
|
|
|
rules.add(rule);
|
|
|
|
if (rule.hasIntlPrefix) {
|
|
ruleSet.hasRuleWithIntlPrefix = true;
|
|
}
|
|
if (rule.hasTrunkPrefix) {
|
|
ruleSet.hasRuleWithTrunkPrefix = true;
|
|
}
|
|
}
|
|
ruleSet.rules = rules;
|
|
ruleSets.add(ruleSet);
|
|
}
|
|
res.ruleSets = ruleSets;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
public void parseDataHeader() {
|
|
int count = value32(0);
|
|
int base = count * 12 + 4;
|
|
int spot = 4;
|
|
for (int i = 0; i < count; i++) {
|
|
String callingCode = valueString(spot);
|
|
spot += 4;
|
|
String country = valueString(spot);
|
|
spot += 4;
|
|
int offset = value32(spot) + base;
|
|
spot += 4;
|
|
|
|
if (country.equals(defaultCountry)) {
|
|
defaultCallingCode = callingCode;
|
|
}
|
|
|
|
countryCallingCode.put(country, callingCode);
|
|
|
|
callingCodeOffsets.put(callingCode, offset);
|
|
ArrayList<String> countries = callingCodeCountries.get(callingCode);
|
|
if (countries == null) {
|
|
countries = new ArrayList<String>();
|
|
callingCodeCountries.put(callingCode, countries);
|
|
}
|
|
countries.add(country);
|
|
}
|
|
|
|
if (defaultCallingCode != null) {
|
|
callingCodeInfo(defaultCallingCode);
|
|
}
|
|
}
|
|
}
|