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, minutes, seconds, what, sign)
59
62 value = float(what[0])
63 value += float(what[1]) / 60.0
64 value += float(what[2]) / 3600.0
65 value += float(what[3]) / 3600000.0
66 return float(what[4]) * value
67
70 what = long(what)
71 exponent = _exponent_of(what, desc) & 0xF
72 base = what // pow(10, exponent) & 0xF
73 return base * 16 + exponent
74
77 exponent = what & 0x0F
78 if exponent > 9:
79 raise dns.exception.SyntaxError("bad %s exponent" % desc)
80 base = (what & 0xF0) >> 4
81 if base > 9:
82 raise dns.exception.SyntaxError("bad %s base" % desc)
83 return long(base) * pow(10, exponent)
84
85
86 -class LOC(dns.rdata.Rdata):
87
88 """LOC record
89
90 @ivar latitude: latitude
91 @type latitude: (int, int, int, int, sign) tuple specifying the degrees, minutes,
92 seconds, milliseconds, and sign of the coordinate.
93 @ivar longitude: longitude
94 @type longitude: (int, int, int, int, sign) tuple specifying the degrees,
95 minutes, seconds, milliseconds, and sign of the coordinate.
96 @ivar altitude: altitude
97 @type altitude: float
98 @ivar size: size of the sphere
99 @type size: float
100 @ivar horizontal_precision: horizontal precision
101 @type horizontal_precision: float
102 @ivar vertical_precision: vertical precision
103 @type vertical_precision: float
104 @see: RFC 1876"""
105
106 __slots__ = ['latitude', 'longitude', 'altitude', 'size',
107 'horizontal_precision', 'vertical_precision']
108
112 """Initialize a LOC record instance.
113
114 The parameters I{latitude} and I{longitude} may be either a 4-tuple
115 of integers specifying (degrees, minutes, seconds, milliseconds),
116 or they may be floating point values specifying the number of
117 degrees. The other parameters are floats. Size, horizontal precision,
118 and vertical precision are specified in centimeters."""
119
120 super(LOC, self).__init__(rdclass, rdtype)
121 if isinstance(latitude, int) or isinstance(latitude, long):
122 latitude = float(latitude)
123 if isinstance(latitude, float):
124 latitude = _float_to_tuple(latitude)
125 self.latitude = latitude
126 if isinstance(longitude, int) or isinstance(longitude, long):
127 longitude = float(longitude)
128 if isinstance(longitude, float):
129 longitude = _float_to_tuple(longitude)
130 self.longitude = longitude
131 self.altitude = float(altitude)
132 self.size = float(size)
133 self.horizontal_precision = float(hprec)
134 self.vertical_precision = float(vprec)
135
136 - def to_text(self, origin=None, relativize=True, **kw):
137 if self.latitude[4] > 0:
138 lat_hemisphere = 'N'
139 lat_degrees = self.latitude[0]
140 else:
141 lat_hemisphere = 'S'
142 lat_degrees = -1 * self.latitude[0]
143 if self.longitude[4] > 0:
144 long_hemisphere = 'E'
145 long_degrees = self.longitude[0]
146 else:
147 long_hemisphere = 'W'
148 long_degrees = -1 * self.longitude[0]
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.2fm %0.2fm %0.2fm" % (
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