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