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