From 4bbc3ff037026c72f3249f59c1b5af69a6ad6d69 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 29 Mar 2010 16:08:11 +0200 Subject: s4-python: Move dnspython to lib/, like the other Python modules This also avoids it from being installed if it's already present on the system. --- lib/dnspython/dns/rdtypes/ANY/LOC.py | 334 +++++++++++++++++++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 lib/dnspython/dns/rdtypes/ANY/LOC.py (limited to 'lib/dnspython/dns/rdtypes/ANY/LOC.py') diff --git a/lib/dnspython/dns/rdtypes/ANY/LOC.py b/lib/dnspython/dns/rdtypes/ANY/LOC.py new file mode 100644 index 0000000000..518dd6010f --- /dev/null +++ b/lib/dnspython/dns/rdtypes/ANY/LOC.py @@ -0,0 +1,334 @@ +# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose with or without fee is hereby granted, +# provided that the above copyright notice and this permission notice +# appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import cStringIO +import struct + +import dns.exception +import dns.rdata + +_pows = (1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, + 100000000L, 1000000000L, 10000000000L) + +def _exponent_of(what, desc): + exp = None + for i in xrange(len(_pows)): + if what // _pows[i] == 0L: + exp = i - 1 + break + if exp is None or exp < 0: + raise dns.exception.SyntaxError("%s value out of bounds" % desc) + return exp + +def _float_to_tuple(what): + if what < 0: + sign = -1 + what *= -1 + else: + sign = 1 + what = long(round(what * 3600000)) + degrees = int(what // 3600000) + what -= degrees * 3600000 + minutes = int(what // 60000) + what -= minutes * 60000 + seconds = int(what // 1000) + what -= int(seconds * 1000) + what = int(what) + return (degrees * sign, minutes, seconds, what) + +def _tuple_to_float(what): + if what[0] < 0: + sign = -1 + value = float(what[0]) * -1 + else: + sign = 1 + value = float(what[0]) + value += float(what[1]) / 60.0 + value += float(what[2]) / 3600.0 + value += float(what[3]) / 3600000.0 + return sign * value + +def _encode_size(what, desc): + what = long(what); + exponent = _exponent_of(what, desc) & 0xF + base = what // pow(10, exponent) & 0xF + return base * 16 + exponent + +def _decode_size(what, desc): + exponent = what & 0x0F + if exponent > 9: + raise dns.exception.SyntaxError("bad %s exponent" % desc) + base = (what & 0xF0) >> 4 + if base > 9: + raise dns.exception.SyntaxError("bad %s base" % desc) + return long(base) * pow(10, exponent) + +class LOC(dns.rdata.Rdata): + """LOC record + + @ivar latitude: latitude + @type latitude: (int, int, int, int) tuple specifying the degrees, minutes, + seconds, and milliseconds of the coordinate. + @ivar longitude: longitude + @type longitude: (int, int, int, int) tuple specifying the degrees, + minutes, seconds, and milliseconds of the coordinate. + @ivar altitude: altitude + @type altitude: float + @ivar size: size of the sphere + @type size: float + @ivar horizontal_precision: horizontal precision + @type horizontal_precision: float + @ivar vertical_precision: vertical precision + @type vertical_precision: float + @see: RFC 1876""" + + __slots__ = ['latitude', 'longitude', 'altitude', 'size', + 'horizontal_precision', 'vertical_precision'] + + def __init__(self, rdclass, rdtype, latitude, longitude, altitude, + size=1.0, hprec=10000.0, vprec=10.0): + """Initialize a LOC record instance. + + The parameters I{latitude} and I{longitude} may be either a 4-tuple + of integers specifying (degrees, minutes, seconds, milliseconds), + or they may be floating point values specifying the number of + degrees. The other parameters are floats.""" + + super(LOC, self).__init__(rdclass, rdtype) + if isinstance(latitude, int) or isinstance(latitude, long): + latitude = float(latitude) + if isinstance(latitude, float): + latitude = _float_to_tuple(latitude) + self.latitude = latitude + if isinstance(longitude, int) or isinstance(longitude, long): + longitude = float(longitude) + if isinstance(longitude, float): + longitude = _float_to_tuple(longitude) + self.longitude = longitude + self.altitude = float(altitude) + self.size = float(size) + self.horizontal_precision = float(hprec) + self.vertical_precision = float(vprec) + + def to_text(self, origin=None, relativize=True, **kw): + if self.latitude[0] > 0: + lat_hemisphere = 'N' + lat_degrees = self.latitude[0] + else: + lat_hemisphere = 'S' + lat_degrees = -1 * self.latitude[0] + if self.longitude[0] > 0: + long_hemisphere = 'E' + long_degrees = self.longitude[0] + else: + long_hemisphere = 'W' + long_degrees = -1 * self.longitude[0] + text = "%d %d %d.%03d %s %d %d %d.%03d %s %0.2fm" % ( + lat_degrees, self.latitude[1], self.latitude[2], self.latitude[3], + lat_hemisphere, long_degrees, self.longitude[1], self.longitude[2], + self.longitude[3], long_hemisphere, self.altitude / 100.0 + ) + + if self.size != 1.0 or self.horizontal_precision != 10000.0 or \ + self.vertical_precision != 10.0: + text += " %0.2fm %0.2fm %0.2fm" % ( + self.size / 100.0, self.horizontal_precision / 100.0, + self.vertical_precision / 100.0 + ) + return text + + def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): + latitude = [0, 0, 0, 0] + longitude = [0, 0, 0, 0] + size = 1.0 + hprec = 10000.0 + vprec = 10.0 + + latitude[0] = tok.get_int() + t = tok.get_string() + if t.isdigit(): + latitude[1] = int(t) + t = tok.get_string() + if '.' in t: + (seconds, milliseconds) = t.split('.') + if not seconds.isdigit(): + raise dns.exception.SyntaxError('bad latitude seconds value') + latitude[2] = int(seconds) + if latitude[2] >= 60: + raise dns.exception.SyntaxError('latitude seconds >= 60') + l = len(milliseconds) + if l == 0 or l > 3 or not milliseconds.isdigit(): + raise dns.exception.SyntaxError('bad latitude milliseconds value') + if l == 1: + m = 100 + elif l == 2: + m = 10 + else: + m = 1 + latitude[3] = m * int(milliseconds) + t = tok.get_string() + elif t.isdigit(): + latitude[2] = int(t) + t = tok.get_string() + if t == 'S': + latitude[0] *= -1 + elif t != 'N': + raise dns.exception.SyntaxError('bad latitude hemisphere value') + + longitude[0] = tok.get_int() + t = tok.get_string() + if t.isdigit(): + longitude[1] = int(t) + t = tok.get_string() + if '.' in t: + (seconds, milliseconds) = t.split('.') + if not seconds.isdigit(): + raise dns.exception.SyntaxError('bad longitude seconds value') + longitude[2] = int(seconds) + if longitude[2] >= 60: + raise dns.exception.SyntaxError('longitude seconds >= 60') + l = len(milliseconds) + if l == 0 or l > 3 or not milliseconds.isdigit(): + raise dns.exception.SyntaxError('bad longitude milliseconds value') + if l == 1: + m = 100 + elif l == 2: + m = 10 + else: + m = 1 + longitude[3] = m * int(milliseconds) + t = tok.get_string() + elif t.isdigit(): + longitude[2] = int(t) + t = tok.get_string() + if t == 'W': + longitude[0] *= -1 + elif t != 'E': + raise dns.exception.SyntaxError('bad longitude hemisphere value') + + t = tok.get_string() + if t[-1] == 'm': + t = t[0 : -1] + altitude = float(t) * 100.0 # m -> cm + + token = tok.get().unescape() + if not token.is_eol_or_eof(): + value = token.value + if value[-1] == 'm': + value = value[0 : -1] + size = float(value) * 100.0 # m -> cm + token = tok.get().unescape() + if not token.is_eol_or_eof(): + value = token.value + if value[-1] == 'm': + value = value[0 : -1] + hprec = float(value) * 100.0 # m -> cm + token = tok.get().unescape() + if not token.is_eol_or_eof(): + value = token.value + if value[-1] == 'm': + value = value[0 : -1] + vprec = float(value) * 100.0 # m -> cm + tok.get_eol() + + return cls(rdclass, rdtype, latitude, longitude, altitude, + size, hprec, vprec) + + from_text = classmethod(from_text) + + def to_wire(self, file, compress = None, origin = None): + if self.latitude[0] < 0: + sign = -1 + degrees = long(-1 * self.latitude[0]) + else: + sign = 1 + degrees = long(self.latitude[0]) + milliseconds = (degrees * 3600000 + + self.latitude[1] * 60000 + + self.latitude[2] * 1000 + + self.latitude[3]) * sign + latitude = 0x80000000L + milliseconds + if self.longitude[0] < 0: + sign = -1 + degrees = long(-1 * self.longitude[0]) + else: + sign = 1 + degrees = long(self.longitude[0]) + milliseconds = (degrees * 3600000 + + self.longitude[1] * 60000 + + self.longitude[2] * 1000 + + self.longitude[3]) * sign + longitude = 0x80000000L + milliseconds + altitude = long(self.altitude) + 10000000L + size = _encode_size(self.size, "size") + hprec = _encode_size(self.horizontal_precision, "horizontal precision") + vprec = _encode_size(self.vertical_precision, "vertical precision") + wire = struct.pack("!BBBBIII", 0, size, hprec, vprec, latitude, + longitude, altitude) + file.write(wire) + + def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): + (version, size, hprec, vprec, latitude, longitude, altitude) = \ + struct.unpack("!BBBBIII", wire[current : current + rdlen]) + if latitude > 0x80000000L: + latitude = float(latitude - 0x80000000L) / 3600000 + else: + latitude = -1 * float(0x80000000L - latitude) / 3600000 + if latitude < -90.0 or latitude > 90.0: + raise dns.exception.FormError("bad latitude") + if longitude > 0x80000000L: + longitude = float(longitude - 0x80000000L) / 3600000 + else: + longitude = -1 * float(0x80000000L - longitude) / 3600000 + if longitude < -180.0 or longitude > 180.0: + raise dns.exception.FormError("bad longitude") + altitude = float(altitude) - 10000000.0 + size = _decode_size(size, "size") + hprec = _decode_size(hprec, "horizontal precision") + vprec = _decode_size(vprec, "vertical precision") + return cls(rdclass, rdtype, latitude, longitude, altitude, + size, hprec, vprec) + + from_wire = classmethod(from_wire) + + def _cmp(self, other): + f = cStringIO.StringIO() + self.to_wire(f) + wire1 = f.getvalue() + f.seek(0) + f.truncate() + other.to_wire(f) + wire2 = f.getvalue() + f.close() + + return cmp(wire1, wire2) + + def _get_float_latitude(self): + return _tuple_to_float(self.latitude) + + def _set_float_latitude(self, value): + self.latitude = _float_to_tuple(value) + + float_latitude = property(_get_float_latitude, _set_float_latitude, + doc="latitude as a floating point value") + + def _get_float_longitude(self): + return _tuple_to_float(self.longitude) + + def _set_float_longitude(self, value): + self.longitude = _float_to_tuple(value) + + float_longitude = property(_get_float_longitude, _set_float_longitude, + doc="longitude as a floating point value") -- cgit