1 /*
2 * This file is part of nmealib.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <nmealib/validate.h>
19
20 #include <nmealib/context.h>
21
22 /** Invalid NMEA character: non-ASCII */
23 static const NmeaInvalidCharacter nmealibInvalidNonAsciiCharsName = {
24 .character = '*', //
25 .description = "non-ASCII character" //
26 };
27
28 /** Invalid NMEA character/description pairs */
29 static const NmeaInvalidCharacter nmealibInvalidCharacters[] = {
30 {
31 .character = '$', //
32 .description = "sentence delimiter" //
33 },
34 {
35 .character = '*', //
36 .description = "checksum field delimiter" //
37 },
38 {
39 .character = '!', //
40 .description = "exclamation mark" //
41 },
42 {
43 .character = '\\', //
44 .description = "backslash" //
45 },
46 {
47 .character = '^', //
48 .description = "power" //
49 },
50 {
51 .character = '~', //
52 .description = "tilde" //
53 },
54 {
55 .character = '\0', //
56 .description = NULL //
57 }//
58 };
59
nmeaValidateIsInvalidCharacter(const char c)60 const NmeaInvalidCharacter *nmeaValidateIsInvalidCharacter(const char c) {
61 size_t i = 0;
62
63 if ((c < 32) //
64 || (c > 126)) {
65 return &nmealibInvalidNonAsciiCharsName;
66 }
67
68 while (nmealibInvalidCharacters[i].description) {
69 if (c == nmealibInvalidCharacters[i].character) {
70 return &nmealibInvalidCharacters[i];
71 }
72
73 i++;
74 }
75
76 return NULL;
77 }
78
nmeaValidateSentenceHasInvalidCharacters(const char * s,const size_t sz)79 const NmeaInvalidCharacter *nmeaValidateSentenceHasInvalidCharacters(const char *s, const size_t sz) {
80 size_t i = 0;
81
82 if (!s //
83 || !sz) {
84 return NULL;
85 }
86
87 for (i = 0; i < sz; i++) {
88 const NmeaInvalidCharacter *invalid = nmeaValidateIsInvalidCharacter(s[i]);
89 if (invalid) {
90 return invalid;
91 }
92 }
93
94 return NULL;
95 }
96
nmeaValidateTime(const NmeaTime * t,const char * prefix,const char * s)97 bool nmeaValidateTime(const NmeaTime *t, const char *prefix, const char *s) {
98 if (!t) {
99 return false;
100 }
101
102 if ((t->hour > 23) //
103 || (t->min > 59) //
104 || (t->sec > 60) //
105 || (t->hsec > 99)) {
106 nmeaContextError("%s parse error: invalid time '%02u:%02u:%02u.%03u' (hh:mm:ss.mmm) in '%s'", prefix, t->hour,
107 t->min, t->sec, t->hsec * 10, s);
108 return false;
109 }
110
111 return true;
112 }
113
nmeaValidateDate(const NmeaTime * t,const char * prefix,const char * s)114 bool nmeaValidateDate(const NmeaTime *t, const char *prefix, const char *s) {
115 if (!t) {
116 return false;
117 }
118
119 if ((t->year < 1900) //
120 || (t->year > 2089) //
121 || (t->mon < 1) //
122 || (t->mon > 12) //
123 || (t->day < 1) //
124 || (t->day > 31)) {
125 nmeaContextError("%s parse error: invalid date '%02u-%02u-%04u' (dd-mm-yyyy) in '%s'", prefix, t->day, t->mon,
126 t->year, s);
127 return false;
128 }
129
130 return true;
131 }
132
nmeaValidateNSEW(char c,const bool ns,const char * prefix,const char * s)133 bool nmeaValidateNSEW(char c, const bool ns, const char *prefix, const char *s) {
134 char cu[] = {
135 0,
136 0,
137 0 };
138
139 if (c) {
140 cu[0] = c;
141 } else {
142 cu[0] = '\\';
143 cu[1] = '0';
144 }
145
146 if (ns) {
147 if ((c != 'N') //
148 && (c != 'S')) {
149 nmeaContextError("%s parse error: invalid North/South '%s' in '%s'", prefix, cu, s);
150 return false;
151 }
152 } else {
153 if ((c != 'E') //
154 && (c != 'W')) {
155 nmeaContextError("%s parse error: invalid East/West '%s' in '%s'", prefix, cu, s);
156 return false;
157 }
158 }
159
160 return true;
161 }
162
nmeaValidateFix(NmeaFix fix,const char * prefix,const char * s)163 bool nmeaValidateFix(NmeaFix fix, const char *prefix, const char *s) {
164 if ((fix < NMEALIB_FIX_FIRST) //
165 || (fix > NMEALIB_FIX_LAST)) {
166 nmeaContextError("%s parse error: invalid fix %d, expected [%d, %d] in '%s'", prefix, fix, NMEALIB_FIX_FIRST,
167 NMEALIB_FIX_LAST, s);
168 return false;
169 }
170
171 return true;
172 }
173
nmeaValidateSignal(NmeaSignal sig,const char * prefix,const char * s)174 bool nmeaValidateSignal(NmeaSignal sig, const char *prefix, const char *s) {
175 if (sig > NMEALIB_SIG_LAST) {
176 nmeaContextError("%s parse error: invalid signal %d, expected [%d, %d] in '%s'", prefix, sig, NMEALIB_SIG_FIRST,
177 NMEALIB_SIG_LAST, s);
178 return false;
179 }
180
181 return true;
182 }
183
nmeaValidateMode(char c,const char * prefix,const char * s)184 bool nmeaValidateMode(char c, const char *prefix, const char *s) {
185 if (!c) {
186 return false;
187 }
188
189 if ((c != 'N') //
190 && (c != 'A') //
191 && (c != 'D') //
192 && (c != 'P') //
193 && (c != 'R') //
194 && (c != 'F') //
195 && (c != 'E') //
196 && (c != 'M') //
197 && (c != 'S')) {
198 nmeaContextError("%s parse error: invalid mode '%c' in '%s'", prefix, c, s);
199 return false;
200 }
201
202 return true;
203 }
204
nmeaValidateSatellite(NmeaSatellite * sat,const char * prefix,const char * s)205 bool nmeaValidateSatellite(NmeaSatellite *sat, const char *prefix, const char *s) {
206 if (!sat) {
207 return false;
208 }
209
210 if ((sat->elevation < -180) //
211 || (sat->elevation > 180)) {
212 nmeaContextError("%s parse error: invalid satellite elevation %d in '%s'", prefix, sat->elevation, s);
213 return false;
214 }
215
216 if (sat->azimuth > 359) {
217 nmeaContextError("%s parse error: invalid satellite azimuth %u in '%s'", prefix, sat->azimuth, s);
218 return false;
219 }
220
221 if (sat->snr > 99) {
222 nmeaContextError("%s parse error: invalid satellite signal %u in '%s'", prefix, sat->snr, s);
223 return false;
224 }
225
226 return true;
227 }
228