001: // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
002:
003: package org.xbill.DNS;
004:
005: import java.io.*;
006: import java.text.*;
007:
008: /**
009: * Location - describes the physical location of hosts, networks, subnets.
010: *
011: * @author Brian Wellington
012: */
013:
014: public class LOCRecord extends Record {
015:
016: private static NumberFormat w2, w3;
017:
018: private long size, hPrecision, vPrecision;
019: private long latitude, longitude, altitude;
020:
021: static {
022: w2 = new DecimalFormat();
023: w2.setMaximumFractionDigits(2);
024: w2.setGroupingUsed(false);
025:
026: w3 = new DecimalFormat();
027: w3.setMaximumFractionDigits(3);
028: w3.setGroupingUsed(false);
029: }
030:
031: LOCRecord() {
032: }
033:
034: Record getObject() {
035: return new LOCRecord();
036: }
037:
038: /**
039: * Creates an LOC Record from the given data
040: * @param latitude The latitude of the center of the sphere
041: * @param longitude The longitude of the center of the sphere
042: * @param altitude The altitude of the center of the sphere, in m
043: * @param size The diameter of a sphere enclosing the described entity, in m.
044: * @param hPrecision The horizontal precision of the data, in m.
045: * @param vPrecision The vertical precision of the data, in m.
046: */
047: public LOCRecord(Name name, int dclass, long ttl, double latitude,
048: double longitude, double altitude, double size,
049: double hPrecision, double vPrecision) {
050: super (name, Type.LOC, dclass, ttl);
051: this .latitude = (long) (latitude * 3600 * 1000 + (1L << 31));
052: this .longitude = (long) (longitude * 3600 * 1000 + (1L << 31));
053: this .altitude = (long) ((altitude + 100000) * 100);
054: this .size = (long) (size * 100);
055: this .hPrecision = (long) (hPrecision * 100);
056: this .vPrecision = (long) (vPrecision * 100);
057: }
058:
059: void rrFromWire(DNSInput in) throws IOException {
060: int version;
061:
062: version = in.readU8();
063: if (version != 0)
064: throw new WireParseException("Invalid LOC version");
065:
066: size = parseLOCformat(in.readU8());
067: hPrecision = parseLOCformat(in.readU8());
068: vPrecision = parseLOCformat(in.readU8());
069: latitude = in.readU32();
070: longitude = in.readU32();
071: altitude = in.readU32();
072: }
073:
074: private long parsePosition(Tokenizer st, String type)
075: throws IOException {
076: boolean isLatitude = type.equals("latitude");
077: int deg = 0, min = 0;
078: double sec = 0;
079: long value;
080: String s;
081:
082: deg = st.getUInt16();
083: if (deg > 180 || (deg > 90 && isLatitude))
084: throw st.exception("Invalid LOC " + type + " degrees");
085:
086: s = st.getString();
087: try {
088: min = Integer.parseInt(s);
089: if (min < 0 || min > 59)
090: throw st.exception("Invalid LOC " + type + " minutes");
091: s = st.getString();
092: sec = Double.parseDouble(s);
093: if (sec < 0 || sec >= 60)
094: throw st.exception("Invalid LOC " + type + " seconds");
095: s = st.getString();
096: } catch (NumberFormatException e) {
097: }
098:
099: if (s.length() != 1)
100: throw st.exception("Invalid LOC " + type);
101:
102: value = (long) (1000 * (sec + 60L * (min + 60L * deg)));
103:
104: char c = Character.toUpperCase(s.charAt(0));
105: if ((isLatitude && c == 'S') || (!isLatitude && c == 'W'))
106: value = -value;
107: else if ((isLatitude && c != 'N') || (!isLatitude && c != 'E'))
108: throw st.exception("Invalid LOC " + type);
109:
110: value += (1L << 31);
111:
112: return value;
113: }
114:
115: private long parseDouble(Tokenizer st, String type,
116: boolean required, long min, long max, long defaultValue)
117: throws IOException {
118: Tokenizer.Token token = st.get();
119: if (token.isEOL()) {
120: if (required)
121: throw st.exception("Invalid LOC " + type);
122: st.unget();
123: return defaultValue;
124: }
125: String s = token.value;
126: if (s.length() > 1 && s.charAt(s.length() - 1) == 'm')
127: s = s.substring(0, s.length() - 1);
128: try {
129: long value = (long) (100 * new Double(s).doubleValue());
130: if (value < min || value > max)
131: throw st.exception("Invalid LOC " + type);
132: return value;
133: } catch (NumberFormatException e) {
134: throw st.exception("Invalid LOC " + type);
135: }
136: }
137:
138: void rdataFromString(Tokenizer st, Name origin) throws IOException {
139: String s = null;
140: int deg, min;
141: double sec;
142:
143: latitude = parsePosition(st, "latitude");
144: longitude = parsePosition(st, "longitude");
145: altitude = parseDouble(st, "altitude", true, -10000000,
146: 4284967295L, 0) + 10000000;
147: size = parseDouble(st, "size", false, 0, 9000000000L, 100);
148: hPrecision = parseDouble(st, "horizontal precision", false, 0,
149: 9000000000L, 1000000);
150: vPrecision = parseDouble(st, "vertical precision", false, 0,
151: 9000000000L, 1000);
152: }
153:
154: private String positionToString(long value, char pos, char neg) {
155: StringBuffer sb = new StringBuffer();
156: char direction;
157:
158: long temp = value - (1L << 31);
159: if (temp < 0) {
160: temp = -temp;
161: direction = neg;
162: } else
163: direction = pos;
164:
165: sb.append(temp / (3600 * 1000)); /* degrees */
166: temp = temp % (3600 * 1000);
167: sb.append(" ");
168:
169: sb.append(temp / (60 * 1000)); /* minutes */
170: temp = temp % (60 * 1000);
171: sb.append(" ");
172:
173: sb.append(w3.format(((double) temp) / 1000)); /* seconds */
174: sb.append(" ");
175:
176: sb.append(direction);
177:
178: return sb.toString();
179: }
180:
181: /** Convert to a String */
182: String rrToString() {
183: StringBuffer sb = new StringBuffer();
184: long temp;
185: char direction;
186:
187: /* Latitude */
188: sb.append(positionToString(latitude, 'N', 'S'));
189: sb.append(" ");
190:
191: /* Latitude */
192: sb.append(positionToString(longitude, 'E', 'W'));
193: sb.append(" ");
194:
195: /* Altitude */
196: sb.append(w2.format((double) (altitude - 10000000) / 100));
197: sb.append("m ");
198:
199: /* Size */
200: sb.append(w2.format((double) size / 100));
201: sb.append("m ");
202:
203: /* Horizontal precision */
204: sb.append(w2.format((double) hPrecision / 100));
205: sb.append("m ");
206:
207: /* Vertical precision */
208: sb.append(w2.format((double) vPrecision / 100));
209: sb.append("m");
210:
211: return sb.toString();
212: }
213:
214: /** Returns the latitude */
215: public double getLatitude() {
216: return ((double) (latitude - (1L << 31))) / (3600 * 1000);
217: }
218:
219: /** Returns the longitude */
220: public double getLongitude() {
221: return ((double) (longitude - (1L << 31))) / (3600 * 1000);
222: }
223:
224: /** Returns the altitude */
225: public double getAltitude() {
226: return ((double) (altitude - 10000000)) / 100;
227: }
228:
229: /** Returns the diameter of the enclosing sphere */
230: public double getSize() {
231: return ((double) size) / 100;
232: }
233:
234: /** Returns the horizontal precision */
235: public double getHPrecision() {
236: return ((double) hPrecision) / 100;
237: }
238:
239: /** Returns the horizontal precision */
240: public double getVPrecision() {
241: return ((double) vPrecision) / 100;
242: }
243:
244: void rrToWire(DNSOutput out, Compression c, boolean canonical) {
245: out.writeU8(0); /* version */
246: out.writeU8(toLOCformat(size));
247: out.writeU8(toLOCformat(hPrecision));
248: out.writeU8(toLOCformat(vPrecision));
249: out.writeU32(latitude);
250: out.writeU32(longitude);
251: out.writeU32(altitude);
252: }
253:
254: private static long parseLOCformat(int b) throws WireParseException {
255: long out = b >> 4;
256: int exp = b & 0xF;
257: if (out > 9 || exp > 9)
258: throw new WireParseException("Invalid LOC Encoding");
259: while (exp-- > 0)
260: out *= 10;
261: return (out);
262: }
263:
264: private byte toLOCformat(long l) {
265: byte exp = 0;
266: while (l > 9) {
267: exp++;
268: l = (l + 5) / 10;
269: }
270: return (byte) ((l << 4) + exp);
271: }
272:
273: }
|