1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
30 _default_size = 100.0
31 _default_hprec = 1000000.0
32 _default_vprec = 1000.0
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
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
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
74 what = long(what)
75 exponent = _exponent_of(what, desc) & 0xF
76 base = what // pow(10, exponent) & 0xF
77 return base * 16 + exponent
78
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
90 -class LOC(dns.rdata.Rdata):
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
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
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():
183 raise dns.exception.SyntaxError(
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():
190 raise dns.exception.SyntaxError(
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():
216 raise dns.exception.SyntaxError(
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():
223 raise dns.exception.SyntaxError(
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
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
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
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
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
313
316
317 float_latitude = property(_get_float_latitude, _set_float_latitude,
318 doc="latitude as a floating point value")
319
322
325
326 float_longitude = property(_get_float_longitude, _set_float_longitude,
327 doc="longitude as a floating point value")
328