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