1 // Copyright (c) 1999-2004 Brian Wellington (bwelling (at) 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 31 LOCRecord() {} 32 33 Record 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 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 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 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 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 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 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 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 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 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 248 getLatitude() { 249 return ((double)(latitude - (1L << 31))) / (3600 * 1000); 250 } 251 252 /** Returns the longitude */ 253 public double 254 getLongitude() { 255 return ((double)(longitude - (1L << 31))) / (3600 * 1000); 256 } 257 258 /** Returns the altitude */ 259 public double 260 getAltitude() { 261 return ((double)(altitude - 10000000)) / 100; 262 } 263 264 /** Returns the diameter of the enclosing sphere */ 265 public double 266 getSize() { 267 return ((double)size) / 100; 268 } 269 270 /** Returns the horizontal precision */ 271 public double 272 getHPrecision() { 273 return ((double)hPrecision) / 100; 274 } 275 276 /** Returns the horizontal precision */ 277 public double 278 getVPrecision() { 279 return ((double)vPrecision) / 100; 280 } 281 282 void 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 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 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