• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2 
3 package org.xbill.DNS;
4 
5 import java.io.*;
6 import java.text.*;
7 
8 /**
9  * Location - describes the physical location of hosts, networks, subnets.
10  *
11  * @author Brian Wellington
12  */
13 
14 public class LOCRecord extends Record {
15 
16 private static final long serialVersionUID = 9058224788126750409L;
17 
18 private static NumberFormat w2, w3;
19 
20 private long size, hPrecision, vPrecision;
21 private long latitude, longitude, altitude;
22 
23 static {
24 	w2 = new DecimalFormat();
25 	w2.setMinimumIntegerDigits(2);
26 
27 	w3 = new DecimalFormat();
28 	w3.setMinimumIntegerDigits(3);
29 }
30 
LOCRecord()31 LOCRecord() {}
32 
33 Record
getObject()34 getObject() {
35 	return new LOCRecord();
36 }
37 
38 /**
39  * Creates an LOC Record from the given data
40  * @param latitude The latitude of the center of the sphere
41  * @param longitude The longitude of the center of the sphere
42  * @param altitude The altitude of the center of the sphere, in m
43  * @param size The diameter of a sphere enclosing the described entity, in m.
44  * @param hPrecision The horizontal precision of the data, in m.
45  * @param vPrecision The vertical precision of the data, in m.
46 */
47 public
LOCRecord(Name name, int dclass, long ttl, double latitude, double longitude, double altitude, double size, double hPrecision, double vPrecision)48 LOCRecord(Name name, int dclass, long ttl, double latitude, double longitude,
49 	  double altitude, double size, double hPrecision, double vPrecision)
50 {
51 	super(name, Type.LOC, dclass, ttl);
52 	this.latitude = (long)(latitude * 3600 * 1000 + (1L << 31));
53 	this.longitude = (long)(longitude * 3600 * 1000 + (1L << 31));
54 	this.altitude = (long)((altitude + 100000) * 100);
55 	this.size = (long)(size * 100);
56 	this.hPrecision = (long)(hPrecision * 100);
57 	this.vPrecision = (long)(vPrecision * 100);
58 }
59 
60 void
rrFromWire(DNSInput in)61 rrFromWire(DNSInput in) throws IOException {
62 	int version;
63 
64 	version = in.readU8();
65 	if (version != 0)
66 		throw new WireParseException("Invalid LOC version");
67 
68 	size = parseLOCformat(in.readU8());
69 	hPrecision = parseLOCformat(in.readU8());
70 	vPrecision = parseLOCformat(in.readU8());
71 	latitude = in.readU32();
72 	longitude = in.readU32();
73 	altitude = in.readU32();
74 }
75 
76 private double
parseFixedPoint(String s)77 parseFixedPoint(String s)
78 {
79 	if (s.matches("^-?\\d+$"))
80 		return Integer.parseInt(s);
81 	else if (s.matches("^-?\\d+\\.\\d*$")) {
82 		String [] parts = s.split("\\.");
83 		double value = Integer.parseInt(parts[0]);
84 		double fraction = Integer.parseInt(parts[1]);
85 		if (value < 0)
86 			fraction *= -1;
87 		int digits = parts[1].length();
88 		return value + (fraction / Math.pow(10, digits));
89 	} else
90 		throw new NumberFormatException();
91 }
92 
93 private long
parsePosition(Tokenizer st, String type)94 parsePosition(Tokenizer st, String type) throws IOException {
95 	boolean isLatitude = type.equals("latitude");
96 	int deg = 0, min = 0;
97 	double sec = 0;
98 	long value;
99 	String s;
100 
101 	deg = st.getUInt16();
102 	if (deg > 180 || (deg > 90 && isLatitude))
103 		throw st.exception("Invalid LOC " + type + " degrees");
104 
105 	s = st.getString();
106 	try {
107 		min = Integer.parseInt(s);
108 		if (min < 0 || min > 59)
109 			throw st.exception("Invalid LOC " + type + " minutes");
110 		s = st.getString();
111 		sec = parseFixedPoint(s);
112 		if (sec < 0 || sec >= 60)
113 			throw st.exception("Invalid LOC " + type + " seconds");
114 		s = st.getString();
115 	} catch (NumberFormatException e) {
116 	}
117 
118 	if (s.length() != 1)
119 		throw st.exception("Invalid LOC " + type);
120 
121 	value = (long) (1000 * (sec + 60L * (min + 60L * deg)));
122 
123 	char c = Character.toUpperCase(s.charAt(0));
124 	if ((isLatitude && c == 'S') || (!isLatitude && c == 'W'))
125 		value = -value;
126 	else if ((isLatitude && c != 'N') || (!isLatitude && c != 'E'))
127 		throw st.exception("Invalid LOC " + type);
128 
129 	value += (1L << 31);
130 
131 	return value;
132 }
133 
134 private long
parseDouble(Tokenizer st, String type, boolean required, long min, long max, long defaultValue)135 parseDouble(Tokenizer st, String type, boolean required, long min, long max,
136 	    long defaultValue)
137 throws IOException
138 {
139 	Tokenizer.Token token = st.get();
140 	if (token.isEOL()) {
141 		if (required)
142 			throw st.exception("Invalid LOC " + type);
143 		st.unget();
144 		return defaultValue;
145 	}
146 	String s = token.value;
147 	if (s.length() > 1 && s.charAt(s.length() - 1) == 'm')
148 		s = s.substring(0, s.length() - 1);
149 	try {
150 		long value = (long)(100 * parseFixedPoint(s));
151 		if (value < min || value > max)
152 			throw st.exception("Invalid LOC " + type);
153 		return value;
154 	}
155 	catch (NumberFormatException e) {
156 		throw st.exception("Invalid LOC " + type);
157 	}
158 }
159 
160 void
rdataFromString(Tokenizer st, Name origin)161 rdataFromString(Tokenizer st, Name origin) throws IOException {
162 	latitude = parsePosition(st, "latitude");
163 	longitude = parsePosition(st, "longitude");
164 	altitude = parseDouble(st, "altitude", true,
165 			       -10000000, 4284967295L, 0) + 10000000;
166 	size = parseDouble(st, "size", false, 0, 9000000000L, 100);
167 	hPrecision = parseDouble(st, "horizontal precision", false,
168 				 0, 9000000000L, 1000000);
169 	vPrecision = parseDouble(st, "vertical precision", false,
170 				 0, 9000000000L, 1000);
171 }
172 
173 private void
renderFixedPoint(StringBuffer sb, NumberFormat formatter, long value, long divisor)174 renderFixedPoint(StringBuffer sb, NumberFormat formatter, long value,
175 		 long divisor)
176 {
177 	sb.append(value / divisor);
178 	value %= divisor;
179 	if (value != 0) {
180 		sb.append(".");
181 		sb.append(formatter.format(value));
182 	}
183 }
184 
185 private String
positionToString(long value, char pos, char neg)186 positionToString(long value, char pos, char neg) {
187 	StringBuffer sb = new StringBuffer();
188 	char direction;
189 
190 	long temp = value - (1L << 31);
191 	if (temp < 0) {
192 		temp = -temp;
193 		direction = neg;
194 	} else
195 		direction = pos;
196 
197 	sb.append(temp / (3600 * 1000)); /* degrees */
198 	temp = temp % (3600 * 1000);
199 	sb.append(" ");
200 
201 	sb.append(temp / (60 * 1000)); /* minutes */
202 	temp = temp % (60 * 1000);
203 	sb.append(" ");
204 
205 	renderFixedPoint(sb, w3, temp, 1000); /* seconds */
206 	sb.append(" ");
207 
208 	sb.append(direction);
209 
210 	return sb.toString();
211 }
212 
213 
214 /** Convert to a String */
215 String
rrToString()216 rrToString() {
217 	StringBuffer sb = new StringBuffer();
218 
219 	/* Latitude */
220 	sb.append(positionToString(latitude, 'N', 'S'));
221 	sb.append(" ");
222 
223 	/* Latitude */
224 	sb.append(positionToString(longitude, 'E', 'W'));
225 	sb.append(" ");
226 
227 	/* Altitude */
228 	renderFixedPoint(sb, w2, altitude - 10000000, 100);
229 	sb.append("m ");
230 
231 	/* Size */
232 	renderFixedPoint(sb, w2, size, 100);
233 	sb.append("m ");
234 
235 	/* Horizontal precision */
236 	renderFixedPoint(sb, w2, hPrecision, 100);
237 	sb.append("m ");
238 
239 	/* Vertical precision */
240 	renderFixedPoint(sb, w2, vPrecision, 100);
241 	sb.append("m");
242 
243 	return sb.toString();
244 }
245 
246 /** Returns the latitude */
247 public double
getLatitude()248 getLatitude() {
249 	return ((double)(latitude - (1L << 31))) / (3600 * 1000);
250 }
251 
252 /** Returns the longitude */
253 public double
getLongitude()254 getLongitude() {
255 	return ((double)(longitude - (1L << 31))) / (3600 * 1000);
256 }
257 
258 /** Returns the altitude */
259 public double
getAltitude()260 getAltitude() {
261 	return ((double)(altitude - 10000000)) / 100;
262 }
263 
264 /** Returns the diameter of the enclosing sphere */
265 public double
getSize()266 getSize() {
267 	return ((double)size) / 100;
268 }
269 
270 /** Returns the horizontal precision */
271 public double
getHPrecision()272 getHPrecision() {
273 	return ((double)hPrecision) / 100;
274 }
275 
276 /** Returns the horizontal precision */
277 public double
getVPrecision()278 getVPrecision() {
279 	return ((double)vPrecision) / 100;
280 }
281 
282 void
rrToWire(DNSOutput out, Compression c, boolean canonical)283 rrToWire(DNSOutput out, Compression c, boolean canonical) {
284 	out.writeU8(0); /* version */
285 	out.writeU8(toLOCformat(size));
286 	out.writeU8(toLOCformat(hPrecision));
287 	out.writeU8(toLOCformat(vPrecision));
288 	out.writeU32(latitude);
289 	out.writeU32(longitude);
290 	out.writeU32(altitude);
291 }
292 
293 private static long
parseLOCformat(int b)294 parseLOCformat(int b) throws WireParseException {
295 	long out = b >> 4;
296 	int exp = b & 0xF;
297 	if (out > 9 || exp > 9)
298 		throw new WireParseException("Invalid LOC Encoding");
299 	while (exp-- > 0)
300 		out *= 10;
301 	return (out);
302 }
303 
304 private int
toLOCformat(long l)305 toLOCformat(long l) {
306 	byte exp = 0;
307 	while (l > 9) {
308 		exp++;
309 		l /= 10;
310 	}
311 	return (int)((l << 4) + exp);
312 }
313 
314 }
315