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