Package dns :: Package rdtypes :: Package ANY :: Module LOC
[hide private]
[frames] | no frames]

Source Code for Module dns.rdtypes.ANY.LOC

  1  # Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. 
  2  # 
  3  # Permission to use, copy, modify, and distribute this software and its 
  4  # documentation for any purpose with or without fee is hereby granted, 
  5  # provided that the above copyright notice and this permission notice 
  6  # appear in all copies. 
  7  # 
  8  # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 
  9  # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 
 10  # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 
 11  # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
 12  # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
 13  # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 
 14  # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
 15   
 16  import struct 
 17   
 18  import dns.exception 
 19  import dns.rdata 
 20  from dns._compat import long, xrange 
 21   
 22   
 23  _pows = tuple(long(10**i) for i in range(0, 11)) 
 24   
 25  # default values are in centimeters 
 26  _default_size = 100.0 
 27  _default_hprec = 1000000.0 
 28  _default_vprec = 1000.0 
29 30 31 -def _exponent_of(what, desc):
32 if what == 0: 33 return 0 34 exp = None 35 for i in xrange(len(_pows)): 36 if what // _pows[i] == long(0): 37 exp = i - 1 38 break 39 if exp is None or exp < 0: 40 raise dns.exception.SyntaxError("%s value out of bounds" % desc) 41 return exp
42
43 44 -def _float_to_tuple(what):
45 if what < 0: 46 sign = -1 47 what *= -1 48 else: 49 sign = 1 50 what = long(round(what * 3600000)) 51 degrees = int(what // 3600000) 52 what -= degrees * 3600000 53 minutes = int(what // 60000) 54 what -= minutes * 60000 55 seconds = int(what // 1000) 56 what -= int(seconds * 1000) 57 what = int(what) 58 return (degrees * sign, minutes, seconds, what)
59
60 61 -def _tuple_to_float(what):
62 if what[0] < 0: 63 sign = -1 64 value = float(what[0]) * -1 65 else: 66 sign = 1 67 value = float(what[0]) 68 value += float(what[1]) / 60.0 69 value += float(what[2]) / 3600.0 70 value += float(what[3]) / 3600000.0 71 return sign * value
72
73 74 -def _encode_size(what, desc):
75 what = long(what) 76 exponent = _exponent_of(what, desc) & 0xF 77 base = what // pow(10, exponent) & 0xF 78 return base * 16 + exponent
79
80 81 -def _decode_size(what, desc):
82 exponent = what & 0x0F 83 if exponent > 9: 84 raise dns.exception.SyntaxError("bad %s exponent" % desc) 85 base = (what & 0xF0) >> 4 86 if base > 9: 87 raise dns.exception.SyntaxError("bad %s base" % desc) 88 return long(base) * pow(10, exponent)
89
90 91 -class LOC(dns.rdata.Rdata):
92 93 """LOC record 94 95 @ivar latitude: latitude 96 @type latitude: (int, int, int, int) tuple specifying the degrees, minutes, 97 seconds, and milliseconds of the coordinate. 98 @ivar longitude: longitude 99 @type longitude: (int, int, int, int) tuple specifying the degrees, 100 minutes, seconds, and milliseconds of the coordinate. 101 @ivar altitude: altitude 102 @type altitude: float 103 @ivar size: size of the sphere 104 @type size: float 105 @ivar horizontal_precision: horizontal precision 106 @type horizontal_precision: float 107 @ivar vertical_precision: vertical precision 108 @type vertical_precision: float 109 @see: RFC 1876""" 110 111 __slots__ = ['latitude', 'longitude', 'altitude', 'size', 112 'horizontal_precision', 'vertical_precision'] 113
114 - def __init__(self, rdclass, rdtype, latitude, longitude, altitude, 115 size=_default_size, hprec=_default_hprec, 116 vprec=_default_vprec):
117 """Initialize a LOC record instance. 118 119 The parameters I{latitude} and I{longitude} may be either a 4-tuple 120 of integers specifying (degrees, minutes, seconds, milliseconds), 121 or they may be floating point values specifying the number of 122 degrees. The other parameters are floats. Size, horizontal precision, 123 and vertical precision are specified in centimeters.""" 124 125 super(LOC, self).__init__(rdclass, rdtype) 126 if isinstance(latitude, int) or isinstance(latitude, long): 127 latitude = float(latitude) 128 if isinstance(latitude, float): 129 latitude = _float_to_tuple(latitude) 130 self.latitude = latitude 131 if isinstance(longitude, int) or isinstance(longitude, long): 132 longitude = float(longitude) 133 if isinstance(longitude, float): 134 longitude = _float_to_tuple(longitude) 135 self.longitude = longitude 136 self.altitude = float(altitude) 137 self.size = float(size) 138 self.horizontal_precision = float(hprec) 139 self.vertical_precision = float(vprec)
140
141 - def to_text(self, origin=None, relativize=True, **kw):
142 if self.latitude[0] > 0: 143 lat_hemisphere = 'N' 144 lat_degrees = self.latitude[0] 145 else: 146 lat_hemisphere = 'S' 147 lat_degrees = -1 * self.latitude[0] 148 if self.longitude[0] > 0: 149 long_hemisphere = 'E' 150 long_degrees = self.longitude[0] 151 else: 152 long_hemisphere = 'W' 153 long_degrees = -1 * self.longitude[0] 154 text = "%d %d %d.%03d %s %d %d %d.%03d %s %0.2fm" % ( 155 lat_degrees, self.latitude[1], self.latitude[2], self.latitude[3], 156 lat_hemisphere, long_degrees, self.longitude[1], self.longitude[2], 157 self.longitude[3], long_hemisphere, self.altitude / 100.0 158 ) 159 160 # do not print default values 161 if self.size != _default_size or \ 162 self.horizontal_precision != _default_hprec or \ 163 self.vertical_precision != _default_vprec: 164 text += " %0.2fm %0.2fm %0.2fm" % ( 165 self.size / 100.0, self.horizontal_precision / 100.0, 166 self.vertical_precision / 100.0 167 ) 168 return text
169 170 @classmethod
171 - def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True):
172 latitude = [0, 0, 0, 0] 173 longitude = [0, 0, 0, 0] 174 size = _default_size 175 hprec = _default_hprec 176 vprec = _default_vprec 177 178 latitude[0] = tok.get_int() 179 t = tok.get_string() 180 if t.isdigit(): 181 latitude[1] = int(t) 182 t = tok.get_string() 183 if '.' in t: 184 (seconds, milliseconds) = t.split('.') 185 if not seconds.isdigit(): 186 raise dns.exception.SyntaxError( 187 'bad latitude seconds value') 188 latitude[2] = int(seconds) 189 if latitude[2] >= 60: 190 raise dns.exception.SyntaxError('latitude seconds >= 60') 191 l = len(milliseconds) 192 if l == 0 or l > 3 or not milliseconds.isdigit(): 193 raise dns.exception.SyntaxError( 194 'bad latitude milliseconds value') 195 if l == 1: 196 m = 100 197 elif l == 2: 198 m = 10 199 else: 200 m = 1 201 latitude[3] = m * int(milliseconds) 202 t = tok.get_string() 203 elif t.isdigit(): 204 latitude[2] = int(t) 205 t = tok.get_string() 206 if t == 'S': 207 latitude[0] *= -1 208 elif t != 'N': 209 raise dns.exception.SyntaxError('bad latitude hemisphere value') 210 211 longitude[0] = tok.get_int() 212 t = tok.get_string() 213 if t.isdigit(): 214 longitude[1] = int(t) 215 t = tok.get_string() 216 if '.' in t: 217 (seconds, milliseconds) = t.split('.') 218 if not seconds.isdigit(): 219 raise dns.exception.SyntaxError( 220 'bad longitude seconds value') 221 longitude[2] = int(seconds) 222 if longitude[2] >= 60: 223 raise dns.exception.SyntaxError('longitude seconds >= 60') 224 l = len(milliseconds) 225 if l == 0 or l > 3 or not milliseconds.isdigit(): 226 raise dns.exception.SyntaxError( 227 'bad longitude milliseconds value') 228 if l == 1: 229 m = 100 230 elif l == 2: 231 m = 10 232 else: 233 m = 1 234 longitude[3] = m * int(milliseconds) 235 t = tok.get_string() 236 elif t.isdigit(): 237 longitude[2] = int(t) 238 t = tok.get_string() 239 if t == 'W': 240 longitude[0] *= -1 241 elif t != 'E': 242 raise dns.exception.SyntaxError('bad longitude hemisphere value') 243 244 t = tok.get_string() 245 if t[-1] == 'm': 246 t = t[0: -1] 247 altitude = float(t) * 100.0 # m -> cm 248 249 token = tok.get().unescape() 250 if not token.is_eol_or_eof(): 251 value = token.value 252 if value[-1] == 'm': 253 value = value[0: -1] 254 size = float(value) * 100.0 # m -> cm 255 token = tok.get().unescape() 256 if not token.is_eol_or_eof(): 257 value = token.value 258 if value[-1] == 'm': 259 value = value[0: -1] 260 hprec = float(value) * 100.0 # m -> cm 261 token = tok.get().unescape() 262 if not token.is_eol_or_eof(): 263 value = token.value 264 if value[-1] == 'm': 265 value = value[0: -1] 266 vprec = float(value) * 100.0 # m -> cm 267 tok.get_eol() 268 269 return cls(rdclass, rdtype, latitude, longitude, altitude, 270 size, hprec, vprec)
271
272 - def to_wire(self, file, compress=None, origin=None):
273 if self.latitude[0] < 0: 274 sign = -1 275 degrees = long(-1 * self.latitude[0]) 276 else: 277 sign = 1 278 degrees = long(self.latitude[0]) 279 milliseconds = (degrees * 3600000 + 280 self.latitude[1] * 60000 + 281 self.latitude[2] * 1000 + 282 self.latitude[3]) * sign 283 latitude = long(0x80000000) + milliseconds 284 if self.longitude[0] < 0: 285 sign = -1 286 degrees = long(-1 * self.longitude[0]) 287 else: 288 sign = 1 289 degrees = long(self.longitude[0]) 290 milliseconds = (degrees * 3600000 + 291 self.longitude[1] * 60000 + 292 self.longitude[2] * 1000 + 293 self.longitude[3]) * sign 294 longitude = long(0x80000000) + milliseconds 295 altitude = long(self.altitude) + long(10000000) 296 size = _encode_size(self.size, "size") 297 hprec = _encode_size(self.horizontal_precision, "horizontal precision") 298 vprec = _encode_size(self.vertical_precision, "vertical precision") 299 wire = struct.pack("!BBBBIII", 0, size, hprec, vprec, latitude, 300 longitude, altitude) 301 file.write(wire)
302 303 @classmethod
304 - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None):
305 (version, size, hprec, vprec, latitude, longitude, altitude) = \ 306 struct.unpack("!BBBBIII", wire[current: current + rdlen]) 307 if latitude > long(0x80000000): 308 latitude = float(latitude - long(0x80000000)) / 3600000 309 else: 310 latitude = -1 * float(long(0x80000000) - latitude) / 3600000 311 if latitude < -90.0 or latitude > 90.0: 312 raise dns.exception.FormError("bad latitude") 313 if longitude > long(0x80000000): 314 longitude = float(longitude - long(0x80000000)) / 3600000 315 else: 316 longitude = -1 * float(long(0x80000000) - longitude) / 3600000 317 if longitude < -180.0 or longitude > 180.0: 318 raise dns.exception.FormError("bad longitude") 319 altitude = float(altitude) - 10000000.0 320 size = _decode_size(size, "size") 321 hprec = _decode_size(hprec, "horizontal precision") 322 vprec = _decode_size(vprec, "vertical precision") 323 return cls(rdclass, rdtype, latitude, longitude, altitude, 324 size, hprec, vprec)
325
326 - def _get_float_latitude(self):
327 return _tuple_to_float(self.latitude)
328
329 - def _set_float_latitude(self, value):
331 332 float_latitude = property(_get_float_latitude, _set_float_latitude, 333 doc="latitude as a floating point value") 334
335 - def _get_float_longitude(self):
336 return _tuple_to_float(self.longitude)
337
338 - def _set_float_longitude(self, value):
340 341 float_longitude = property(_get_float_longitude, _set_float_longitude, 342 doc="longitude as a floating point value")
343