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('bad latitude seconds value')
168 latitude[2] = int(seconds)
169 if latitude[2] >= 60:
170 raise dns.exception.SyntaxError('latitude seconds >= 60')
171 l = len(milliseconds)
172 if l == 0 or l > 3 or not milliseconds.isdigit():
173 raise dns.exception.SyntaxError('bad latitude milliseconds value')
174 if l == 1:
175 m = 100
176 elif l == 2:
177 m = 10
178 else:
179 m = 1
180 latitude[3] = m * int(milliseconds)
181 t = tok.get_string()
182 elif t.isdigit():
183 latitude[2] = int(t)
184 t = tok.get_string()
185 if t == 'S':
186 latitude[0] *= -1
187 elif t != 'N':
188 raise dns.exception.SyntaxError('bad latitude hemisphere value')
189
190 longitude[0] = tok.get_int()
191 t = tok.get_string()
192 if t.isdigit():
193 longitude[1] = int(t)
194 t = tok.get_string()
195 if '.' in t:
196 (seconds, milliseconds) = t.split('.')
197 if not seconds.isdigit():
198 raise dns.exception.SyntaxError('bad longitude seconds value')
199 longitude[2] = int(seconds)
200 if longitude[2] >= 60:
201 raise dns.exception.SyntaxError('longitude seconds >= 60')
202 l = len(milliseconds)
203 if l == 0 or l > 3 or not milliseconds.isdigit():
204 raise dns.exception.SyntaxError('bad longitude milliseconds value')
205 if l == 1:
206 m = 100
207 elif l == 2:
208 m = 10
209 else:
210 m = 1
211 longitude[3] = m * int(milliseconds)
212 t = tok.get_string()
213 elif t.isdigit():
214 longitude[2] = int(t)
215 t = tok.get_string()
216 if t == 'W':
217 longitude[0] *= -1
218 elif t != 'E':
219 raise dns.exception.SyntaxError('bad longitude hemisphere value')
220
221 t = tok.get_string()
222 if t[-1] == 'm':
223 t = t[0 : -1]
224 altitude = float(t) * 100.0
225
226 token = tok.get().unescape()
227 if not token.is_eol_or_eof():
228 value = token.value
229 if value[-1] == 'm':
230 value = value[0 : -1]
231 size = float(value) * 100.0
232 token = tok.get().unescape()
233 if not token.is_eol_or_eof():
234 value = token.value
235 if value[-1] == 'm':
236 value = value[0 : -1]
237 hprec = float(value) * 100.0
238 token = tok.get().unescape()
239 if not token.is_eol_or_eof():
240 value = token.value
241 if value[-1] == 'm':
242 value = value[0 : -1]
243 vprec = float(value) * 100.0
244 tok.get_eol()
245
246 return cls(rdclass, rdtype, latitude, longitude, altitude,
247 size, hprec, vprec)
248
249 from_text = classmethod(from_text)
250
251 - def to_wire(self, file, compress = None, origin = None):
252 if self.latitude[0] < 0:
253 sign = -1
254 degrees = long(-1 * self.latitude[0])
255 else:
256 sign = 1
257 degrees = long(self.latitude[0])
258 milliseconds = (degrees * 3600000 +
259 self.latitude[1] * 60000 +
260 self.latitude[2] * 1000 +
261 self.latitude[3]) * sign
262 latitude = 0x80000000L + milliseconds
263 if self.longitude[0] < 0:
264 sign = -1
265 degrees = long(-1 * self.longitude[0])
266 else:
267 sign = 1
268 degrees = long(self.longitude[0])
269 milliseconds = (degrees * 3600000 +
270 self.longitude[1] * 60000 +
271 self.longitude[2] * 1000 +
272 self.longitude[3]) * sign
273 longitude = 0x80000000L + milliseconds
274 altitude = long(self.altitude) + 10000000L
275 size = _encode_size(self.size, "size")
276 hprec = _encode_size(self.horizontal_precision, "horizontal precision")
277 vprec = _encode_size(self.vertical_precision, "vertical precision")
278 wire = struct.pack("!BBBBIII", 0, size, hprec, vprec, latitude,
279 longitude, altitude)
280 file.write(wire)
281
282 - def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None):
283 (version, size, hprec, vprec, latitude, longitude, altitude) = \
284 struct.unpack("!BBBBIII", wire[current : current + rdlen])
285 if latitude > 0x80000000L:
286 latitude = float(latitude - 0x80000000L) / 3600000
287 else:
288 latitude = -1 * float(0x80000000L - latitude) / 3600000
289 if latitude < -90.0 or latitude > 90.0:
290 raise dns.exception.FormError("bad latitude")
291 if longitude > 0x80000000L:
292 longitude = float(longitude - 0x80000000L) / 3600000
293 else:
294 longitude = -1 * float(0x80000000L - longitude) / 3600000
295 if longitude < -180.0 or longitude > 180.0:
296 raise dns.exception.FormError("bad longitude")
297 altitude = float(altitude) - 10000000.0
298 size = _decode_size(size, "size")
299 hprec = _decode_size(hprec, "horizontal precision")
300 vprec = _decode_size(vprec, "vertical precision")
301 return cls(rdclass, rdtype, latitude, longitude, altitude,
302 size, hprec, vprec)
303
304 from_wire = classmethod(from_wire)
305
306 - def _cmp(self, other):
307 f = cStringIO.StringIO()
308 self.to_wire(f)
309 wire1 = f.getvalue()
310 f.seek(0)
311 f.truncate()
312 other.to_wire(f)
313 wire2 = f.getvalue()
314 f.close()
315
316 return cmp(wire1, wire2)
317
320
323
324 float_latitude = property(_get_float_latitude, _set_float_latitude,
325 doc="latitude as a floating point value")
326
329
332
333 float_longitude = property(_get_float_longitude, _set_float_longitude,
334 doc="longitude as a floating point value")
335