xref: /openbsd/usr.bin/dig/lib/dns/rdata/generic/loc_29.c (revision d415bd75)
1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /* $Id: loc_29.c,v 1.13 2020/09/14 08:40:43 florian Exp $ */
18 
19 /* Reviewed: Wed Mar 15 18:13:09 PST 2000 by explorer */
20 
21 /* RFC1876 */
22 
23 #ifndef RDATA_GENERIC_LOC_29_C
24 #define RDATA_GENERIC_LOC_29_C
25 
26 static inline isc_result_t
27 totext_loc(ARGS_TOTEXT) {
28 	int d1, m1, s1, fs1;
29 	int d2, m2, s2, fs2;
30 	unsigned long latitude;
31 	unsigned long longitude;
32 	unsigned long altitude;
33 	int north;
34 	int east;
35 	int below;
36 	isc_region_t sr;
37 	char buf[sizeof("89 59 59.999 N 179 59 59.999 E "
38 			"42849672.95m 90000000m 90000000m 90000000m")];
39 	char sbuf[sizeof("90000000m")];
40 	char hbuf[sizeof("90000000m")];
41 	char vbuf[sizeof("90000000m")];
42 	unsigned char size, hp, vp;
43 	unsigned long poweroften[8] = { 1, 10, 100, 1000,
44 					10000, 100000, 1000000, 10000000 };
45 
46 	UNUSED(tctx);
47 
48 	REQUIRE(rdata->type == dns_rdatatype_loc);
49 	REQUIRE(rdata->length != 0);
50 
51 	dns_rdata_toregion(rdata, &sr);
52 
53 	if (sr.base[0] != 0)
54 		return (ISC_R_NOTIMPLEMENTED);
55 
56 	REQUIRE(rdata->length == 16);
57 
58 	size = sr.base[1];
59 	INSIST((size&0x0f) < 10 && (size>>4) < 10);
60 	if ((size&0x0f)> 1) {
61 		snprintf(sbuf, sizeof(sbuf),
62 			 "%lum", (size>>4) * poweroften[(size&0x0f)-2]);
63 	} else {
64 		snprintf(sbuf, sizeof(sbuf),
65 			 "0.%02lum", (size>>4) * poweroften[(size&0x0f)]);
66 	}
67 	hp = sr.base[2];
68 	INSIST((hp&0x0f) < 10 && (hp>>4) < 10);
69 	if ((hp&0x0f)> 1) {
70 		snprintf(hbuf, sizeof(hbuf),
71 			"%lum", (hp>>4) * poweroften[(hp&0x0f)-2]);
72 	} else {
73 		snprintf(hbuf, sizeof(hbuf),
74 			 "0.%02lum", (hp>>4) * poweroften[(hp&0x0f)]);
75 	}
76 	vp = sr.base[3];
77 	INSIST((vp&0x0f) < 10 && (vp>>4) < 10);
78 	if ((vp&0x0f)> 1) {
79 		snprintf(vbuf, sizeof(vbuf),
80 			 "%lum", (vp>>4) * poweroften[(vp&0x0f)-2]);
81 	} else {
82 		snprintf(vbuf, sizeof(vbuf),
83 			 "0.%02lum", (vp>>4) * poweroften[(vp&0x0f)]);
84 	}
85 	isc_region_consume(&sr, 4);
86 
87 	latitude = uint32_fromregion(&sr);
88 	isc_region_consume(&sr, 4);
89 	if (latitude >= 0x80000000) {
90 		north = 1;
91 		latitude -= 0x80000000;
92 	} else {
93 		north = 0;
94 		latitude = 0x80000000 - latitude;
95 	}
96 	fs1 = (int)(latitude % 1000);
97 	latitude /= 1000;
98 	s1 = (int)(latitude % 60);
99 	latitude /= 60;
100 	m1 = (int)(latitude % 60);
101 	latitude /= 60;
102 	d1 = (int)latitude;
103 	INSIST(latitude <= 90U);
104 
105 	longitude = uint32_fromregion(&sr);
106 	isc_region_consume(&sr, 4);
107 	if (longitude >= 0x80000000) {
108 		east = 1;
109 		longitude -= 0x80000000;
110 	} else {
111 		east = 0;
112 		longitude = 0x80000000 - longitude;
113 	}
114 	fs2 = (int)(longitude % 1000);
115 	longitude /= 1000;
116 	s2 = (int)(longitude % 60);
117 	longitude /= 60;
118 	m2 = (int)(longitude % 60);
119 	longitude /= 60;
120 	d2 = (int)longitude;
121 	INSIST(longitude <= 180U);
122 
123 	altitude = uint32_fromregion(&sr);
124 	isc_region_consume(&sr, 4);
125 	if (altitude < 10000000U) {
126 		below = 1;
127 		altitude = 10000000 - altitude;
128 	} else {
129 		below =0;
130 		altitude -= 10000000;
131 	}
132 
133 	snprintf(buf, sizeof(buf),
134 		 "%d %d %d.%03d %s %d %d %d.%03d %s %s%lu.%02lum %s %s %s",
135 		 d1, m1, s1, fs1, north ? "N" : "S",
136 		 d2, m2, s2, fs2, east ? "E" : "W",
137 		 below ? "-" : "", altitude/100, altitude % 100,
138 		 sbuf, hbuf, vbuf);
139 
140 	return (isc_str_tobuffer(buf, target));
141 }
142 
143 static inline isc_result_t
144 fromwire_loc(ARGS_FROMWIRE) {
145 	isc_region_t sr;
146 	unsigned char c;
147 	unsigned long latitude;
148 	unsigned long longitude;
149 
150 	REQUIRE(type == dns_rdatatype_loc);
151 
152 	UNUSED(type);
153 	UNUSED(rdclass);
154 	UNUSED(dctx);
155 	UNUSED(options);
156 
157 	isc_buffer_activeregion(source, &sr);
158 	if (sr.length < 1)
159 		return (ISC_R_UNEXPECTEDEND);
160 	if (sr.base[0] != 0) {
161 		/* Treat as unknown. */
162 		isc_buffer_forward(source, sr.length);
163 		return (isc_mem_tobuffer(target, sr.base, sr.length));
164 	}
165 	if (sr.length < 16)
166 		return (ISC_R_UNEXPECTEDEND);
167 
168 	/*
169 	 * Size.
170 	 */
171 	c = sr.base[1];
172 	if (c != 0)
173 		if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
174 			return (ISC_R_RANGE);
175 
176 	/*
177 	 * Horizontal precision.
178 	 */
179 	c = sr.base[2];
180 	if (c != 0)
181 		if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
182 			return (ISC_R_RANGE);
183 
184 	/*
185 	 * Vertical precision.
186 	 */
187 	c = sr.base[3];
188 	if (c != 0)
189 		if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
190 			return (ISC_R_RANGE);
191 	isc_region_consume(&sr, 4);
192 
193 	/*
194 	 * Latitude.
195 	 */
196 	latitude = uint32_fromregion(&sr);
197 	if (latitude < (0x80000000UL - 90 * 3600000) ||
198 	    latitude > (0x80000000UL + 90 * 3600000))
199 		return (ISC_R_RANGE);
200 	isc_region_consume(&sr, 4);
201 
202 	/*
203 	 * Longitude.
204 	 */
205 	longitude = uint32_fromregion(&sr);
206 	if (longitude < (0x80000000UL - 180 * 3600000) ||
207 	    longitude > (0x80000000UL + 180 * 3600000))
208 		return (ISC_R_RANGE);
209 
210 	/*
211 	 * Altitude.
212 	 * All values possible.
213 	 */
214 
215 	isc_buffer_activeregion(source, &sr);
216 	isc_buffer_forward(source, 16);
217 	return (isc_mem_tobuffer(target, sr.base, 16));
218 }
219 
220 static inline isc_result_t
221 towire_loc(ARGS_TOWIRE) {
222 	UNUSED(cctx);
223 
224 	REQUIRE(rdata->type == dns_rdatatype_loc);
225 	REQUIRE(rdata->length != 0);
226 
227 	return (isc_mem_tobuffer(target, rdata->data, rdata->length));
228 }
229 
230 #endif	/* RDATA_GENERIC_LOC_29_C */
231