![JAR search and dependency download from the Maven repository](/logo.png)
com.subgraph.orchid.geoip.CountryCodeService Maven / Gradle / Ivy
package com.subgraph.orchid.geoip;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Logger;
import com.subgraph.orchid.data.IPv4Address;
public class CountryCodeService {
private final static Logger logger = Logger.getLogger(CountryCodeService.class.getName());
private final static String DATABASE_FILENAME = "GeoIP.dat";
private final static int COUNTRY_BEGIN = 16776960;
private final static int STANDARD_RECORD_LENGTH = 3;
private final static int MAX_RECORD_LENGTH = 4;
private final static CountryCodeService DEFAULT_INSTANCE = new CountryCodeService();
public static CountryCodeService getInstance() {
return DEFAULT_INSTANCE;
}
private static final String[] COUNTRY_CODES = { "--", "AP", "EU", "AD", "AE",
"AF", "AG", "AI", "AL", "AM", "CW", "AO", "AQ", "AR", "AS", "AT",
"AU", "AW", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI",
"BJ", "BM", "BN", "BO", "BR", "BS", "BT", "BV", "BW", "BY", "BZ",
"CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN",
"CO", "CR", "CU", "CV", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM",
"DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ",
"FK", "FM", "FO", "FR", "SX", "GA", "GB", "GD", "GE", "GF", "GH",
"GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW",
"GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN",
"IO", "IQ", "IR", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH",
"KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC",
"LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD",
"MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS",
"MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF",
"NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE",
"PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS", "PT", "PW",
"PY", "QA", "RE", "RO", "RU", "RW", "SA", "SB", "SC", "SD", "SE",
"SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "ST",
"SV", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TM",
"TN", "TO", "TL", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM",
"US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF",
"WS", "YE", "YT", "RS", "ZA", "ZM", "ME", "ZW", "A1", "A2", "O1",
"AX", "GG", "IM", "JE", "BL", "MF", "BQ", "SS", "O1" };
private final byte[] database;
public CountryCodeService() {
this.database = loadDatabase();
}
private static byte[] loadDatabase() {
final InputStream input = openDatabaseStream();
if(input == null) {
logger.warning("Failed to open '"+ DATABASE_FILENAME + "' database file for country code lookups");
return null;
}
try {
return loadEntireStream(input);
} catch (IOException e) {
logger.warning("IO error reading database file for country code lookups");
return null;
} finally {
try {
input.close();
} catch (IOException e) { }
}
}
private static InputStream openDatabaseStream() {
final InputStream input = tryResourceOpen();
if(input != null) {
return input;
} else {
return tryFilesystemOpen();
}
}
private static InputStream tryFilesystemOpen() {
final File dataDir = new File(System.getProperty("user.dir"), "data");
final File dbFile = new File(dataDir, DATABASE_FILENAME);
if(!dbFile.canRead()) {
return null;
}
try {
return new FileInputStream(dbFile);
} catch (FileNotFoundException e) {
return null;
}
}
private static InputStream tryResourceOpen() {
return CountryCodeService.class.getResourceAsStream("/data/"+ DATABASE_FILENAME);
}
private static byte[] loadEntireStream(InputStream input) throws IOException {
final ByteArrayOutputStream output = new ByteArrayOutputStream(4096);
copy(input, output);
return output.toByteArray();
}
private static int copy(InputStream input, OutputStream output) throws IOException {
final byte[] buffer = new byte[4096];
int count = 0;
int n = 0;
while((n = input.read(buffer)) != -1) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
public String getCountryCodeForAddress(IPv4Address address) {
return COUNTRY_CODES[seekCountry(address)];
}
private int seekCountry(IPv4Address address) {
if(database == null) {
return 0;
}
final byte[] record = new byte[2 * MAX_RECORD_LENGTH];
final int[] x = new int[2];
final long ip = address.getAddressData() & 0xFFFFFFFFL;
int offset = 0;
for(int depth = 31; depth >= 0; depth--) {
loadRecord(offset, record);
x[0] = unpackRecordValue(record, 0);
x[1] = unpackRecordValue(record, 1);
int xx = ((ip & (1 << depth)) > 0) ? (x[1]) : (x[0]);
if(xx >= COUNTRY_BEGIN) {
final int idx = xx - COUNTRY_BEGIN;
if(idx < 0 || idx > COUNTRY_CODES.length) {
logger.warning("Invalid index calculated looking up country code record for ("+ address +") idx = "+ idx);
return 0;
} else {
return idx;
}
} else {
offset = xx;
}
}
logger.warning("No record found looking up country code record for ("+ address + ")");
return 0;
}
private void loadRecord(int offset, byte[] recordBuffer) {
final int dbOffset = 2 * STANDARD_RECORD_LENGTH * offset;
System.arraycopy(database, dbOffset, recordBuffer, 0, recordBuffer.length);
}
private int unpackRecordValue(byte[] record, int idx) {
final int valueOffset = idx * STANDARD_RECORD_LENGTH;
int value = 0;
for(int i = 0; i < STANDARD_RECORD_LENGTH; i++) {
int octet = record[valueOffset + i] & 0xFF;
value += (octet << (i * 8));
}
return value;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy