diff options
Diffstat (limited to 'src/org/xbill/DNS/LOCRecord.java')
-rw-r--r-- | src/org/xbill/DNS/LOCRecord.java | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/src/org/xbill/DNS/LOCRecord.java b/src/org/xbill/DNS/LOCRecord.java new file mode 100644 index 0000000..4eddc15 --- /dev/null +++ b/src/org/xbill/DNS/LOCRecord.java @@ -0,0 +1,314 @@ +// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org) + +package org.xbill.DNS; + +import java.io.*; +import java.text.*; + +/** + * Location - describes the physical location of hosts, networks, subnets. + * + * @author Brian Wellington + */ + +public class LOCRecord extends Record { + +private static final long serialVersionUID = 9058224788126750409L; + +private static NumberFormat w2, w3; + +private long size, hPrecision, vPrecision; +private long latitude, longitude, altitude; + +static { + w2 = new DecimalFormat(); + w2.setMinimumIntegerDigits(2); + + w3 = new DecimalFormat(); + w3.setMinimumIntegerDigits(3); +} + +LOCRecord() {} + +Record +getObject() { + return new LOCRecord(); +} + +/** + * Creates an LOC Record from the given data + * @param latitude The latitude of the center of the sphere + * @param longitude The longitude of the center of the sphere + * @param altitude The altitude of the center of the sphere, in m + * @param size The diameter of a sphere enclosing the described entity, in m. + * @param hPrecision The horizontal precision of the data, in m. + * @param vPrecision The vertical precision of the data, in m. +*/ +public +LOCRecord(Name name, int dclass, long ttl, double latitude, double longitude, + double altitude, double size, double hPrecision, double vPrecision) +{ + super(name, Type.LOC, dclass, ttl); + this.latitude = (long)(latitude * 3600 * 1000 + (1L << 31)); + this.longitude = (long)(longitude * 3600 * 1000 + (1L << 31)); + this.altitude = (long)((altitude + 100000) * 100); + this.size = (long)(size * 100); + this.hPrecision = (long)(hPrecision * 100); + this.vPrecision = (long)(vPrecision * 100); +} + +void +rrFromWire(DNSInput in) throws IOException { + int version; + + version = in.readU8(); + if (version != 0) + throw new WireParseException("Invalid LOC version"); + + size = parseLOCformat(in.readU8()); + hPrecision = parseLOCformat(in.readU8()); + vPrecision = parseLOCformat(in.readU8()); + latitude = in.readU32(); + longitude = in.readU32(); + altitude = in.readU32(); +} + +private double +parseFixedPoint(String s) +{ + if (s.matches("^-?\\d+$")) + return Integer.parseInt(s); + else if (s.matches("^-?\\d+\\.\\d*$")) { + String [] parts = s.split("\\."); + double value = Integer.parseInt(parts[0]); + double fraction = Integer.parseInt(parts[1]); + if (value < 0) + fraction *= -1; + int digits = parts[1].length(); + return value + (fraction / Math.pow(10, digits)); + } else + throw new NumberFormatException(); +} + +private long +parsePosition(Tokenizer st, String type) throws IOException { + boolean isLatitude = type.equals("latitude"); + int deg = 0, min = 0; + double sec = 0; + long value; + String s; + + deg = st.getUInt16(); + if (deg > 180 || (deg > 90 && isLatitude)) + throw st.exception("Invalid LOC " + type + " degrees"); + + s = st.getString(); + try { + min = Integer.parseInt(s); + if (min < 0 || min > 59) + throw st.exception("Invalid LOC " + type + " minutes"); + s = st.getString(); + sec = parseFixedPoint(s); + if (sec < 0 || sec >= 60) + throw st.exception("Invalid LOC " + type + " seconds"); + s = st.getString(); + } catch (NumberFormatException e) { + } + + if (s.length() != 1) + throw st.exception("Invalid LOC " + type); + + value = (long) (1000 * (sec + 60L * (min + 60L * deg))); + + char c = Character.toUpperCase(s.charAt(0)); + if ((isLatitude && c == 'S') || (!isLatitude && c == 'W')) + value = -value; + else if ((isLatitude && c != 'N') || (!isLatitude && c != 'E')) + throw st.exception("Invalid LOC " + type); + + value += (1L << 31); + + return value; +} + +private long +parseDouble(Tokenizer st, String type, boolean required, long min, long max, + long defaultValue) +throws IOException +{ + Tokenizer.Token token = st.get(); + if (token.isEOL()) { + if (required) + throw st.exception("Invalid LOC " + type); + st.unget(); + return defaultValue; + } + String s = token.value; + if (s.length() > 1 && s.charAt(s.length() - 1) == 'm') + s = s.substring(0, s.length() - 1); + try { + long value = (long)(100 * parseFixedPoint(s)); + if (value < min || value > max) + throw st.exception("Invalid LOC " + type); + return value; + } + catch (NumberFormatException e) { + throw st.exception("Invalid LOC " + type); + } +} + +void +rdataFromString(Tokenizer st, Name origin) throws IOException { + latitude = parsePosition(st, "latitude"); + longitude = parsePosition(st, "longitude"); + altitude = parseDouble(st, "altitude", true, + -10000000, 4284967295L, 0) + 10000000; + size = parseDouble(st, "size", false, 0, 9000000000L, 100); + hPrecision = parseDouble(st, "horizontal precision", false, + 0, 9000000000L, 1000000); + vPrecision = parseDouble(st, "vertical precision", false, + 0, 9000000000L, 1000); +} + +private void +renderFixedPoint(StringBuffer sb, NumberFormat formatter, long value, + long divisor) +{ + sb.append(value / divisor); + value %= divisor; + if (value != 0) { + sb.append("."); + sb.append(formatter.format(value)); + } +} + +private String +positionToString(long value, char pos, char neg) { + StringBuffer sb = new StringBuffer(); + char direction; + + long temp = value - (1L << 31); + if (temp < 0) { + temp = -temp; + direction = neg; + } else + direction = pos; + + sb.append(temp / (3600 * 1000)); /* degrees */ + temp = temp % (3600 * 1000); + sb.append(" "); + + sb.append(temp / (60 * 1000)); /* minutes */ + temp = temp % (60 * 1000); + sb.append(" "); + + renderFixedPoint(sb, w3, temp, 1000); /* seconds */ + sb.append(" "); + + sb.append(direction); + + return sb.toString(); +} + + +/** Convert to a String */ +String +rrToString() { + StringBuffer sb = new StringBuffer(); + + /* Latitude */ + sb.append(positionToString(latitude, 'N', 'S')); + sb.append(" "); + + /* Latitude */ + sb.append(positionToString(longitude, 'E', 'W')); + sb.append(" "); + + /* Altitude */ + renderFixedPoint(sb, w2, altitude - 10000000, 100); + sb.append("m "); + + /* Size */ + renderFixedPoint(sb, w2, size, 100); + sb.append("m "); + + /* Horizontal precision */ + renderFixedPoint(sb, w2, hPrecision, 100); + sb.append("m "); + + /* Vertical precision */ + renderFixedPoint(sb, w2, vPrecision, 100); + sb.append("m"); + + return sb.toString(); +} + +/** Returns the latitude */ +public double +getLatitude() { + return ((double)(latitude - (1L << 31))) / (3600 * 1000); +} + +/** Returns the longitude */ +public double +getLongitude() { + return ((double)(longitude - (1L << 31))) / (3600 * 1000); +} + +/** Returns the altitude */ +public double +getAltitude() { + return ((double)(altitude - 10000000)) / 100; +} + +/** Returns the diameter of the enclosing sphere */ +public double +getSize() { + return ((double)size) / 100; +} + +/** Returns the horizontal precision */ +public double +getHPrecision() { + return ((double)hPrecision) / 100; +} + +/** Returns the horizontal precision */ +public double +getVPrecision() { + return ((double)vPrecision) / 100; +} + +void +rrToWire(DNSOutput out, Compression c, boolean canonical) { + out.writeU8(0); /* version */ + out.writeU8(toLOCformat(size)); + out.writeU8(toLOCformat(hPrecision)); + out.writeU8(toLOCformat(vPrecision)); + out.writeU32(latitude); + out.writeU32(longitude); + out.writeU32(altitude); +} + +private static long +parseLOCformat(int b) throws WireParseException { + long out = b >> 4; + int exp = b & 0xF; + if (out > 9 || exp > 9) + throw new WireParseException("Invalid LOC Encoding"); + while (exp-- > 0) + out *= 10; + return (out); +} + +private int +toLOCformat(long l) { + byte exp = 0; + while (l > 9) { + exp++; + l /= 10; + } + return (int)((l << 4) + exp); +} + +} |