1 /*
2  * This file is Copyright (c) 2010-2018 by the GPSD project
3  * SPDX-License-Identifier: BSD-2-clause
4  */
5 
6 #include "gpsd_config.h"  /* must be before all includes */
7 
8 #include <string.h>
9 #include <ctype.h>
10 #include <assert.h>
11 
12 #include "gpsd.h"
13 
14 /*
15  * gpsd_packetdump()
16  *
17  * if binbuf is printable, just return a copy of it
18  * otherwise) convert a binary string to a hex string and return that
19  *
20  * *scbuf   -- the buffer to fill with hex
21  * scbuflen -- sizeof(scbuf)
22  * *binbuf  -- the binary to convert to hex and place in scbuf
23  * binbuflen -- sizeof(binbuf)
24  *
25  * scbuflen needs to be 2x binbuflen to hold the hex conversion
26  */
27 
gpsd_packetdump(char * scbuf,size_t scbuflen,char * binbuf,size_t binbuflen)28 const char *gpsd_packetdump(char *scbuf, size_t scbuflen,
29 			    char *binbuf, size_t binbuflen)
30 {
31     char *cp;
32     bool printable = true;
33 
34     assert(binbuf != NULL);
35     for (cp = binbuf; cp < binbuf + binbuflen; cp++)
36 	if (!isprint((unsigned char) *cp) && !isspace((unsigned char) *cp)) {
37 	    printable = false;
38 	    break;	/* no need to keep iterating */
39         }
40     if (printable)
41 	return binbuf;
42     else
43 	return gpsd_hexdump(scbuf, scbuflen, binbuf, binbuflen);
44 }
45 
gpsd_hexdump(char * scbuf,size_t scbuflen,char * binbuf,size_t binbuflen)46 const char *gpsd_hexdump(char *scbuf, size_t scbuflen,
47 					  char *binbuf, size_t binbuflen)
48 {
49 #ifndef SQUELCH_ENABLE
50     size_t i, j = 0;
51     size_t len =
52 	(size_t) ((binbuflen >
53 		   MAX_PACKET_LENGTH) ? MAX_PACKET_LENGTH : binbuflen);
54     const char *ibuf = (const char *)binbuf;
55     const char *hexchar = "0123456789abcdef";
56 
57     if (NULL == binbuf || 0 == binbuflen)
58 	return "";
59 
60     for (i = 0; i < len && j < (scbuflen - 3); i++) {
61 	scbuf[j++] = hexchar[(ibuf[i] & 0xf0) >> 4];
62 	scbuf[j++] = hexchar[ibuf[i] & 0x0f];
63     }
64     scbuf[j] = '\0';
65 #else /* SQUELCH defined */
66     scbuf[0] = '\0';
67     (void)scbuflen;
68     (void)binbuf;
69     (void)binbuflen;
70 #endif /* SQUELCH_ENABLE */
71     return scbuf;
72 }
73 
hex2bin(const char * s)74 static int hex2bin(const char *s)
75 {
76     int a, b;
77 
78     a = s[0] & 0xff;
79     b = s[1] & 0xff;
80 
81     if ((a >= 'a') && (a <= 'f'))
82 	a = a + 10 - 'a';
83     else if ((a >= 'A') && (a <= 'F'))
84 	a = a + 10 - 'A';
85     else if ((a >= '0') && (a <= '9'))
86 	a -= '0';
87     else
88 	return -1;
89 
90     if ((b >= 'a') && (b <= 'f'))
91 	b = b + 10 - 'a';
92     else if ((b >= 'A') && (b <= 'F'))
93 	b = b + 10 - 'A';
94     else if ((b >= '0') && (b <= '9'))
95 	b -= '0';
96     else
97 	return -1;
98 
99     return ((a << 4) + b);
100 }
101 
gpsd_hexpack(const char * src,char * dst,size_t len)102 int gpsd_hexpack(const char *src, char *dst, size_t len)
103 /* hex2bin source string to destination - destination can be same as source */
104 {
105     int i, j;
106 
107     j = (int)(strlen(src) / 2);
108     if ((j < 1) || ((size_t) j > len))
109 	return -2;
110 
111     for (i = 0; i < j; i++) {
112 	int k;
113 	if ((k = hex2bin(src + i * 2)) != -1)
114 	    dst[i] = (char)(k & 0xff);
115 	else
116 	    return -1;
117     }
118     (void)memset(dst + i, '\0', (size_t) (len - i));
119     return j;
120 }
121 
122 
hex_escapes(char * cooked,const char * raw)123 ssize_t hex_escapes(char *cooked, const char *raw)
124 /* interpret C-style hex escapes */
125 {
126     char c, *cookend;
127 
128     for (cookend = cooked; *raw != '\0'; raw++)
129 	if (*raw != '\\')
130 	    *cookend++ = *raw;
131 	else {
132 	    switch (*++raw) {
133 	    case 'b':
134 		*cookend++ = '\b';
135 		break;
136 	    case 'e':
137 		*cookend++ = '\x1b';
138 		break;
139 	    case 'f':
140 		*cookend++ = '\f';
141 		break;
142 	    case 'n':
143 		*cookend++ = '\n';
144 		break;
145 	    case 'r':
146 		*cookend++ = '\r';
147 		break;
148 	    case 't':
149 		*cookend++ = '\r';
150 		break;
151 	    case 'v':
152 		*cookend++ = '\v';
153 		break;
154 	    case 'x':
155 		switch (*++raw) {
156 		case '0':
157 		    c = (char)0x00;
158 		    break;
159 		case '1':
160 		    c = (char)0x10;
161 		    break;
162 		case '2':
163 		    c = (char)0x20;
164 		    break;
165 		case '3':
166 		    c = (char)0x30;
167 		    break;
168 		case '4':
169 		    c = (char)0x40;
170 		    break;
171 		case '5':
172 		    c = (char)0x50;
173 		    break;
174 		case '6':
175 		    c = (char)0x60;
176 		    break;
177 		case '7':
178 		    c = (char)0x70;
179 		    break;
180 		case '8':
181 		    c = (char)0x80;
182 		    break;
183 		case '9':
184 		    c = (char)0x90;
185 		    break;
186 		case 'A':
187 		case 'a':
188 		    c = (char)0xa0;
189 		    break;
190 		case 'B':
191 		case 'b':
192 		    c = (char)0xb0;
193 		    break;
194 		case 'C':
195 		case 'c':
196 		    c = (char)0xc0;
197 		    break;
198 		case 'D':
199 		case 'd':
200 		    c = (char)0xd0;
201 		    break;
202 		case 'E':
203 		case 'e':
204 		    c = (char)0xe0;
205 		    break;
206 		case 'F':
207 		case 'f':
208 		    c = (char)0xf0;
209 		    break;
210 		default:
211 		    return -1;
212 		}
213 		switch (*++raw) {
214 		case '0':
215 		    c += 0x00;
216 		    break;
217 		case '1':
218 		    c += 0x01;
219 		    break;
220 		case '2':
221 		    c += 0x02;
222 		    break;
223 		case '3':
224 		    c += 0x03;
225 		    break;
226 		case '4':
227 		    c += 0x04;
228 		    break;
229 		case '5':
230 		    c += 0x05;
231 		    break;
232 		case '6':
233 		    c += 0x06;
234 		    break;
235 		case '7':
236 		    c += 0x07;
237 		    break;
238 		case '8':
239 		    c += 0x08;
240 		    break;
241 		case '9':
242 		    c += 0x09;
243 		    break;
244 		case 'A':
245 		case 'a':
246 		    c += 0x0a;
247 		    break;
248 		case 'B':
249 		case 'b':
250 		    c += 0x0b;
251 		    break;
252 		case 'C':
253 		case 'c':
254 		    c += 0x0c;
255 		    break;
256 		case 'D':
257 		case 'd':
258 		    c += 0x0d;
259 		    break;
260 		case 'E':
261 		case 'e':
262 		    c += 0x0e;
263 		    break;
264 		case 'F':
265 		case 'f':
266 		    c += 0x0f;
267 		    break;
268 		default:
269 		    return -2;
270 		}
271 		*cookend++ = c;
272 		break;
273 	    case '\\':
274 		*cookend++ = '\\';
275 		break;
276 	    default:
277 		return -3;
278 	    }
279 	}
280     return (ssize_t) (cookend - cooked);
281 }
282