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