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