]>
Commit | Line | Data |
---|---|---|
a9e2e5ef BH |
1 | #include "utility.hh" |
2 | #include <cstdio> | |
c6a60874 | 3 | #include <math.h> |
a9e2e5ef BH |
4 | #include <cstdlib> |
5 | #include <sys/types.h> | |
a9e2e5ef BH |
6 | #include <string> |
7 | #include <errno.h> | |
c6a60874 | 8 | #include "dnsrecords.hh" |
20177d1d | 9 | |
a9e2e5ef BH |
10 | static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000, |
11 | 1000000,10000000,100000000,1000000000}; | |
12 | ||
a9e2e5ef | 13 | /* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer.*/ |
49a06471 | 14 | static uint8_t precsize_aton(const char **strptr) |
a9e2e5ef BH |
15 | { |
16 | unsigned int mval = 0, cmval = 0; | |
49a06471 | 17 | uint8_t retval = 0; |
a9e2e5ef BH |
18 | const char *cp; |
19 | int exponent; | |
20 | int mantissa; | |
21 | ||
22 | cp = *strptr; | |
23 | ||
24 | while (isdigit(*cp)) | |
25 | mval = mval * 10 + (*cp++ - '0'); | |
26 | ||
27 | if (*cp == '.') { /* centimeters */ | |
28 | cp++; | |
29 | if (isdigit(*cp)) { | |
30 | cmval = (*cp++ - '0') * 10; | |
31 | if (isdigit(*cp)) { | |
4957a608 | 32 | cmval += (*cp++ - '0'); |
a9e2e5ef BH |
33 | } |
34 | } | |
35 | } | |
36 | cmval = (mval * 100) + cmval; | |
37 | ||
38 | for (exponent = 0; exponent < 9; exponent++) | |
39 | if (cmval < poweroften[exponent+1]) | |
40 | break; | |
41 | ||
42 | mantissa = cmval / poweroften[exponent]; | |
43 | if (mantissa > 9) | |
44 | mantissa = 9; | |
45 | ||
46 | retval = (mantissa << 4) | exponent; | |
47 | ||
48 | *strptr = cp; | |
49 | ||
50 | return (retval); | |
51 | } | |
52 | ||
53 | /* converts ascii lat/lon to unsigned encoded 32-bit number. | |
54 | * moves pointer. */ | |
092f210a | 55 | static uint32_t |
a9e2e5ef BH |
56 | latlon2ul(const char **latlonstrptr, int *which) |
57 | { | |
58 | const char *cp; | |
092f210a | 59 | uint32_t retval; |
a9e2e5ef BH |
60 | int deg = 0, min = 0, secs = 0, secsfrac = 0; |
61 | ||
62 | cp = *latlonstrptr; | |
63 | ||
64 | while (isdigit(*cp)) | |
65 | deg = deg * 10 + (*cp++ - '0'); | |
66 | ||
67 | while (isspace(*cp)) | |
68 | cp++; | |
69 | ||
70 | if (!(isdigit(*cp))) | |
71 | goto fndhemi; | |
72 | ||
73 | while (isdigit(*cp)) | |
74 | min = min * 10 + (*cp++ - '0'); | |
c6a60874 | 75 | |
a9e2e5ef BH |
76 | while (isspace(*cp)) |
77 | cp++; | |
78 | ||
79 | if (!(isdigit(*cp))) | |
80 | goto fndhemi; | |
81 | ||
82 | while (isdigit(*cp)) | |
83 | secs = secs * 10 + (*cp++ - '0'); | |
84 | ||
85 | if (*cp == '.') { /* decimal seconds */ | |
86 | cp++; | |
87 | if (isdigit(*cp)) { | |
88 | secsfrac = (*cp++ - '0') * 100; | |
89 | if (isdigit(*cp)) { | |
4957a608 BH |
90 | secsfrac += (*cp++ - '0') * 10; |
91 | if (isdigit(*cp)) { | |
92 | secsfrac += (*cp++ - '0'); | |
93 | } | |
a9e2e5ef BH |
94 | } |
95 | } | |
96 | } | |
97 | ||
98 | while (!isspace(*cp)) /* if any trailing garbage */ | |
99 | cp++; | |
100 | ||
101 | while (isspace(*cp)) | |
102 | cp++; | |
103 | ||
104 | fndhemi: | |
105 | switch (*cp) { | |
106 | case 'N': case 'n': | |
107 | case 'E': case 'e': | |
108 | retval = ((unsigned)1<<31) | |
109 | + (((((deg * 60) + min) * 60) + secs) * 1000) | |
110 | + secsfrac; | |
111 | break; | |
112 | case 'S': case 's': | |
113 | case 'W': case 'w': | |
114 | retval = ((unsigned)1<<31) | |
115 | - (((((deg * 60) + min) * 60) + secs) * 1000) | |
116 | - secsfrac; | |
117 | break; | |
118 | default: | |
119 | retval = 0; /* invalid value -- indicates error */ | |
120 | break; | |
121 | } | |
122 | ||
123 | switch (*cp) { | |
124 | case 'N': case 'n': | |
125 | case 'S': case 's': | |
126 | *which = 1; /* latitude */ | |
127 | break; | |
128 | case 'E': case 'e': | |
129 | case 'W': case 'w': | |
130 | *which = 2; /* longitude */ | |
131 | break; | |
132 | default: | |
133 | *which = 0; /* error */ | |
134 | break; | |
135 | } | |
136 | ||
137 | cp++; /* skip the hemisphere */ | |
138 | ||
139 | while (!isspace(*cp)) /* if any trailing garbage */ | |
140 | cp++; | |
141 | ||
142 | while (isspace(*cp)) /* move to next field */ | |
143 | cp++; | |
144 | ||
145 | *latlonstrptr = cp; | |
146 | ||
147 | return (retval); | |
148 | } | |
149 | ||
c6a60874 BH |
150 | void LOCRecordContent::report(void) |
151 | { | |
152 | regist(1, ns_t_loc, &make, &make, "LOC"); | |
153 | } | |
154 | ||
155 | DNSRecordContent* LOCRecordContent::make(const string& content) | |
a9e2e5ef | 156 | { |
c6a60874 BH |
157 | return new LOCRecordContent(content); |
158 | } | |
159 | ||
160 | ||
161 | void LOCRecordContent::toPacket(DNSPacketWriter& pw) | |
162 | { | |
163 | pw.xfr8BitInt(d_version); | |
164 | pw.xfr8BitInt(d_size); | |
165 | pw.xfr8BitInt(d_horizpre); | |
166 | pw.xfr8BitInt(d_vertpre); | |
167 | ||
168 | pw.xfr32BitInt(d_latitude); | |
169 | pw.xfr32BitInt(d_longitude); | |
170 | pw.xfr32BitInt(d_altitude); | |
171 | } | |
172 | ||
173 | LOCRecordContent::DNSRecordContent* LOCRecordContent::make(const DNSRecord &dr, PacketReader& pr) | |
174 | { | |
175 | LOCRecordContent* ret=new LOCRecordContent(); | |
176 | pr.xfr8BitInt(ret->d_version); | |
177 | pr.xfr8BitInt(ret->d_size); | |
178 | pr.xfr8BitInt(ret->d_horizpre); | |
179 | pr.xfr8BitInt(ret->d_vertpre); | |
180 | ||
181 | pr.xfr32BitInt(ret->d_latitude); | |
182 | pr.xfr32BitInt(ret->d_longitude); | |
183 | pr.xfr32BitInt(ret->d_altitude); | |
184 | ||
185 | return ret; | |
186 | } | |
187 | ||
188 | LOCRecordContent::LOCRecordContent(const string& content, const string& zone) : DNSRecordContent(ns_t_loc) | |
189 | { | |
190 | // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m | |
191 | // convert this to d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude | |
192 | d_version = 0; | |
193 | ||
a9e2e5ef | 194 | const char *cp, *maxcp; |
a9e2e5ef | 195 | |
092f210a | 196 | uint32_t lltemp1 = 0, lltemp2 = 0; |
a9e2e5ef | 197 | int altmeters = 0, altfrac = 0, altsign = 1; |
c6a60874 BH |
198 | d_horizpre = 0x16; /* default = 1e6 cm = 10000.00m = 10km */ |
199 | d_vertpre = 0x13; /* default = 1e3 cm = 10.00m */ | |
200 | d_size = 0x12; /* default = 1e2 cm = 1.00m */ | |
a9e2e5ef BH |
201 | int which1 = 0, which2 = 0; |
202 | ||
203 | cp = content.c_str(); | |
204 | maxcp = cp + strlen(content.c_str()); | |
205 | ||
206 | lltemp1 = latlon2ul(&cp, &which1); | |
a9e2e5ef BH |
207 | lltemp2 = latlon2ul(&cp, &which2); |
208 | ||
209 | switch (which1 + which2) { | |
210 | case 3: /* 1 + 2, the only valid combination */ | |
211 | if ((which1 == 1) && (which2 == 2)) { /* normal case */ | |
c6a60874 BH |
212 | d_latitude = lltemp1; |
213 | d_longitude = lltemp2; | |
a9e2e5ef | 214 | } else if ((which1 == 2) && (which2 == 1)) {/*reversed*/ |
c6a60874 BH |
215 | d_latitude = lltemp1; |
216 | d_longitude = lltemp2; | |
a9e2e5ef BH |
217 | } else { /* some kind of brokenness */ |
218 | return; | |
219 | } | |
220 | break; | |
221 | default: /* we didn't get one of each */ | |
222 | return; | |
223 | } | |
224 | ||
225 | /* altitude */ | |
226 | if (*cp == '-') { | |
227 | altsign = -1; | |
228 | cp++; | |
229 | } | |
230 | ||
231 | if (*cp == '+') | |
232 | cp++; | |
233 | ||
234 | while (isdigit(*cp)) | |
235 | altmeters = altmeters * 10 + (*cp++ - '0'); | |
236 | ||
237 | if (*cp == '.') { /* decimal meters */ | |
238 | cp++; | |
239 | if (isdigit(*cp)) { | |
240 | altfrac = (*cp++ - '0') * 10; | |
241 | if (isdigit(*cp)) { | |
4957a608 | 242 | altfrac += (*cp++ - '0'); |
a9e2e5ef BH |
243 | } |
244 | } | |
245 | } | |
246 | ||
c6a60874 | 247 | d_altitude = (10000000 + (altsign * (altmeters * 100 + altfrac))); |
a9e2e5ef BH |
248 | |
249 | while (!isspace(*cp) && (cp < maxcp)) | |
250 | /* if trailing garbage or m */ | |
251 | cp++; | |
252 | ||
253 | while (isspace(*cp) && (cp < maxcp)) | |
254 | cp++; | |
255 | ||
256 | ||
257 | if (cp >= maxcp) | |
258 | goto defaults; | |
259 | ||
c6a60874 | 260 | d_size = precsize_aton(&cp); |
a9e2e5ef BH |
261 | |
262 | while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/ | |
263 | cp++; | |
264 | ||
265 | while (isspace(*cp) && (cp < maxcp)) | |
266 | cp++; | |
267 | ||
268 | if (cp >= maxcp) | |
269 | goto defaults; | |
270 | ||
c6a60874 | 271 | d_horizpre = precsize_aton(&cp); |
a9e2e5ef BH |
272 | |
273 | while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/ | |
274 | cp++; | |
275 | ||
276 | while (isspace(*cp) && (cp < maxcp)) | |
277 | cp++; | |
278 | ||
279 | if (cp >= maxcp) | |
280 | goto defaults; | |
281 | ||
c6a60874 | 282 | d_vertpre = precsize_aton(&cp); |
a9e2e5ef BH |
283 | |
284 | defaults: | |
c6a60874 BH |
285 | ; |
286 | } | |
287 | ||
288 | ||
289 | string LOCRecordContent::getZoneRepresentation() const | |
290 | { | |
291 | // convert d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude to: | |
292 | // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m | |
293 | ||
294 | double latitude= ((int32_t)d_latitude - (1<<31))/3600000.0; | |
295 | double longitude=((int32_t)d_longitude - (1<<31))/3600000.0; | |
296 | double altitude= ((int32_t)d_altitude )/100 - 100000; | |
297 | ||
298 | double size=0.01*((d_size>>4)&0xf); | |
299 | int count=d_size & 0xf; | |
300 | while(count--) | |
301 | size*=10; | |
a9e2e5ef | 302 | |
c6a60874 BH |
303 | double horizpre=0.01*((d_horizpre>>4) & 0xf); |
304 | count=d_horizpre&0xf; | |
305 | while(count--) | |
306 | horizpre*=10; | |
307 | ||
308 | double vertpre=0.01*((d_vertpre>>4)&0xf); | |
309 | count=d_vertpre&0xf; | |
310 | while(count--) | |
311 | vertpre*=10; | |
312 | ||
313 | double remlat=60.0*(latitude-(int)latitude); | |
314 | double remlong=60.0*(longitude-(int)longitude); | |
315 | char ret[80]; | |
316 | snprintf(ret,sizeof(ret)-1,"%d %d %2.03f %c %d %d %2.03f %c %.2fm %.2fm %.2fm %.2fm", | |
4957a608 BH |
317 | abs((int)latitude), abs((int) ((latitude-(int)latitude)*60)), |
318 | fabs((double)((remlat-(int)remlat)*60.0)), | |
319 | latitude>0 ? 'N' : 'S', | |
320 | abs((int)longitude), abs((int) ((longitude-(int)longitude)*60)), | |
321 | fabs((double)((remlong-(int)remlong)*60.0)), | |
322 | longitude>0 ? 'E' : 'W', | |
323 | altitude, size, horizpre, vertpre); | |
c6a60874 BH |
324 | |
325 | return ret; | |
a9e2e5ef | 326 | } |