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