aboutsummaryrefslogtreecommitdiff
path: root/src/org/xbill/DNS/LOCRecord.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/xbill/DNS/LOCRecord.java')
-rw-r--r--src/org/xbill/DNS/LOCRecord.java314
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);
+}
+
+}