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