dnspython  1.16.0
About: dnspython is a DNS toolkit (for Python 2.x) that supports almost all record types.
  Fossies Dox: dnspython-1.16.0.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

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