libdap Updated for version 3.21.1
libdap4 is an implementation of OPeNDAP's DAP protocol.
parser-util.cc
Go to the documentation of this file.
1
2// -*- mode: c++; c-basic-offset:4 -*-
3
4// This file is part of libdap, A C++ implementation of the OPeNDAP Data
5// Access Protocol.
6
7// Copyright (c) 2002,2003 OPeNDAP, Inc.
8// Author: James Gallagher <jgallagher@opendap.org>
9//
10// This library is free software; you can redistribute it and/or
11// modify it under the terms of the GNU Lesser General Public
12// License as published by the Free Software Foundation; either
13// version 2.1 of the License, or (at your option) any later version.
14//
15// This library is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18// Lesser General Public License for more details.
19//
20// You should have received a copy of the GNU Lesser General Public
21// License along with this library; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23//
24// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25
26// (c) COPYRIGHT URI/MIT 1995-1999
27// Please read the full copyright statement in the file COPYRIGHT_URI.
28//
29// Authors:
30// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
31
32// These functions are utility functions used by the various DAP parsers (the
33// DAS, DDS and constraint expression parsers).
34// jhrg 9/7/95
35
36#include "config.h"
37
38#include <cassert>
39#include <cerrno>
40#include <cmath>
41#include <cstdlib>
42#include <cstring>
43
44#include <iostream>
45#include <sstream>
46
47// We wrap VC++ 6.x strtod() to account for a short comming
48// in that function in regards to "NaN".
49#ifdef WIN32
50#include <limits>
51double w32strtod(const char *, char **);
52#endif
53
54#include "Error.h"
55#include "debug.h"
56#include "dods-limits.h"
57#include "parser.h" // defines constants such as ID_MAX
58#include "util.h" // Jose Garcia: for append_long_to_string.
59
60using std::cerr;
61using std::endl;
62
63#ifdef WIN32
64// VC++ 6.x strtod() doesn't recognize "NaN". Account for it
65// by wrapping it around a check for the Nan string. Use of
66// the product is obsolete as of 1/2007, but it is unknown if
67// the issue is still there in later releases of that product.
68// ROM - 01/2007
69double w32strtod(const char *val, char **ptr) {
70 // Convert the two char arrays to compare to strings.
71 string *sval = new string(val);
72 string *snan = new string("NaN");
73
74 // If val doesn't contain "NaN|Nan|nan|etc", use strtod as
75 // provided.
76 if (stricmp(sval->c_str(), snan->c_str()) != 0)
77 return (strtod(val, ptr));
78
79 // But if it does, return the bit pattern for Nan and point
80 // the parsing ptr arg at the trailing '\0'.
81 *ptr = (char *)val + strlen(val);
82 return (std::numeric_limits<double>::quiet_NaN());
83}
84#endif
85
86namespace libdap {
87
88// Deprecated, but still used by the HDF4 EOS server code.
89void parse_error(parser_arg *arg, const char *msg, const int line_num, const char *context) {
90 // Jose Garcia
91 // This assert(s) is (are) only for developing purposes
92 // For production servers remove it by compiling with NDEBUG
93 assert(arg);
94 assert(msg);
95
96 arg->set_status(FALSE);
97
98 string oss = "";
99
100 if (line_num != 0) {
101 oss += "Error parsing the text on line ";
102 append_long_to_string(line_num, 10, oss);
103 } else {
104 oss += "Parse error.";
105 }
106
107 if (context)
108 oss += (string) " at or near: " + context + (string) "\n" + msg + (string) "\n";
109 else
110 oss += (string) "\n" + msg + (string) "\n";
111
112 arg->set_error(new Error(unknown_error, oss));
113}
114
115void parse_error(const char *msg, const int line_num, const char *context) {
116 // Jose Garcia
117 // This assert(s) is (are) only for developing purposes
118 // For production servers remove it by compiling with NDEBUG
119 assert(msg);
120
121 string oss = "";
122
123 if (line_num != 0) {
124 oss += "Error parsing the text on line ";
125 append_long_to_string(line_num, 10, oss);
126 } else {
127 oss += "Parse error.";
128 }
129
130 if (context)
131 oss += (string) " at or near: " + context + (string) "\n" + msg + (string) "\n";
132 else
133 oss += (string) "\n" + msg + (string) "\n";
134
135 throw Error(malformed_expr, oss);
136}
137
138// context comes from the parser and will always be a char * unless the
139// parsers change dramatically.
140void parse_error(const string &msg, const int line_num, const char *context) {
141 parse_error(msg.c_str(), line_num, context);
142}
143
144#if 0
145// Remove this since it is not used and contains a potential (low level) vulnerability.
146// jhrg 3/7/22
147void save_str(char *dst, const char *src, const int line_num)
148{
149 if (strlen(src) >= ID_MAX)
150 parse_error(string("The word `") + string(src)
151 + string("' is too long (it should be no longer than ")
152 + long_to_string(ID_MAX) + string(")."), line_num);
153
154 strncpy(dst, src, ID_MAX);
155 dst[ID_MAX - 1] = '\0'; /* in case ... */
156}
157#endif
158
159void save_str(string &dst, const char *src, const int) { dst = src; }
160
161bool is_keyword(string id, const string &keyword) {
162 downcase(id);
163 id = prune_spaces(id);
164 DBG(cerr << "is_keyword: " << keyword << " = " << id << endl);
165 return id == keyword;
166}
167
178int check_byte(const char *val) {
179 char *ptr;
180 long v = strtol(val, &ptr, 0);
181
182 if ((v == 0 && val == ptr) || *ptr != '\0') {
183 return FALSE;
184 }
185
186 DBG(cerr << "v: " << v << endl);
187
188 // We're very liberal here with values. Anything that can fit into 8 bits
189 // is allowed through. Clients will have to deal with the fact that the
190 // ASCII representation for the value might need to be tweaked. This is
191 // especially the case for Java clients where Byte datatypes are
192 // signed. 3/20/2000 jhrg
193 if ((v < 0 && v < DODS_SCHAR_MIN) || (v > 0 && static_cast<unsigned long>(v) > DODS_UCHAR_MAX))
194 return FALSE;
195
196 return TRUE;
197}
198
199// This version of check_int will pass base 8, 10 and 16 numbers when they
200// use the ANSI standard for string representation of those number bases.
201
202int check_int16(const char *val) {
203 char *ptr;
204 long v = strtol(val, &ptr, 0); // `0' --> use val to determine base
205
206 if ((v == 0 && val == ptr) || *ptr != '\0') {
207 return FALSE;
208 }
209 // Don't use the constant from limits.h, use the ones in dods-limits.h
210 if (v > DODS_SHRT_MAX || v < DODS_SHRT_MIN) {
211 return FALSE;
212 }
213
214 return TRUE;
215}
216
217int check_uint16(const char *val) {
218 char *ptr;
219 unsigned long v = strtol(val, &ptr, 0);
220
221 if ((v == 0 && val == ptr) || *ptr != '\0') {
222 return FALSE;
223 }
224
225 if (v > DODS_USHRT_MAX) {
226 return FALSE;
227 }
228
229 return TRUE;
230}
231
232int check_int32(const char *val) {
233 char *ptr;
234 errno = 0;
235 long v = strtol(val, &ptr, 0); // `0' --> use val to determine base
236
237 if ((v == 0 && val == ptr) || *ptr != '\0') {
238 return FALSE;
239 }
240
241 // We need to check errno since strtol return clamps on overflow so the
242 // check against the DODS values below will always pass, even for out of
243 // bounds values in the string. mjohnson 7/20/09
244 if (errno == ERANGE) {
245 return FALSE;
246 }
247 // This could be combined with the above, or course, but I'm making it
248 // separate to highlight the test. On 64-bit linux boxes 'long' may be
249 // 64-bits and so 'v' can hold more than a DODS_INT32. jhrg 3/23/10
250 else if (v > DODS_INT_MAX || v < DODS_INT_MIN) {
251 return FALSE;
252 } else {
253 return TRUE;
254 }
255}
256
257int check_uint32(const char *val) {
258 // Eat whitespace and check for an initial '-' sign...
259 // strtoul allows an initial minus. mjohnson
260 const char *c = val;
261 while (c && isspace(*c)) {
262 c++;
263 }
264 if (c && (*c == '-')) {
265 return FALSE;
266 }
267
268 char *ptr;
269 errno = 0;
270 unsigned long v = strtoul(val, &ptr, 0);
271
272 if ((v == 0 && val == ptr) || *ptr != '\0') {
273 return FALSE;
274 }
275
276 // check overflow first, or the below check is invalid due to
277 // clamping to the maximum value by strtoul
278 // maybe consider using long long for these checks? mjohnson
279 if (errno == ERANGE) {
280 return FALSE;
281 }
282 // See above.
283 else if (v > DODS_UINT_MAX) {
284 return FALSE;
285 } else {
286 return TRUE;
287 }
288}
289
290int check_int32(const char *val, int &v) {
291 char *ptr;
292 errno = 0;
293 long tmp = strtol(val, &ptr, 0); // `0' --> use val to determine base
294
295 if ((tmp == 0 && val == ptr) || *ptr != '\0') {
296 return FALSE;
297 }
298
299 // We need to check errno since strtol return clamps on overflow so the
300 // check against the DODS values below will always pass, even for out of
301 // bounds values in the string. mjohnson 7/20/09
302 if (errno == ERANGE) {
303 return FALSE;
304 }
305 // This could be combined with the above, or course, but I'm making it
306 // separate to highlight the test. On 64-bit linux boxes 'long' may be
307 // 64-bits and so 'v' can hold more than a DODS_INT32. jhrg 3/23/10
308 else if (tmp > DODS_INT_MAX || tmp < DODS_INT_MIN) {
309 return FALSE;
310 } else {
311 v = (int)tmp;
312 return TRUE;
313 }
314}
315
316int check_uint32(const char *val, unsigned int &v) {
317 // Eat whitespace and check for an initial '-' sign...
318 // strtoul allows an initial minus. mjohnson
319 const char *c = val;
320 while (c && isspace(*c)) {
321 c++;
322 }
323 if (c && (*c == '-')) {
324 return FALSE;
325 }
326
327 char *ptr;
328 errno = 0;
329 unsigned long tmp = strtoul(val, &ptr, 0);
330
331 if ((tmp == 0 && val == ptr) || *ptr != '\0') {
332 return FALSE;
333 }
334
335 // check overflow first, or the below check is invalid due to
336 // clamping to the maximum value by strtoul
337 // maybe consider using long long for these checks? mjohnson
338 if (errno == ERANGE) {
339 return FALSE;
340 }
341 // See above.
342 else if (tmp > DODS_UINT_MAX) {
343 return FALSE;
344 } else {
345 v = (unsigned int)tmp;
346 return TRUE;
347 }
348}
349
350int check_int64(const char *val) {
351 char *ptr;
352 errno = 0;
353 long long v = strtoll(val, &ptr, 0); // `0' --> use val to determine base
354
355 if ((v == 0 && val == ptr) || *ptr != '\0') {
356 return FALSE;
357 }
358
359 // We need to check errno since strtol return clamps on overflow so the
360 // check against the DODS values below will always pass, even for out of
361 // bounds values in the string. mjohnson 7/20/09
362 if (errno == ERANGE) {
363 return FALSE;
364 }
365#if 0
366 // This could be combined with the above, or course, but I'm making it
367 // separate to highlight the test. On 64-bit linux boxes 'long' may be
368 // 64-bits and so 'v' can hold more than a DODS_INT32. jhrg 3/23/10
369 //
370 // Removed - Coverity says it can never be false. Makes sense. jhrg 5/10/16
371 else if (v <= DODS_LLONG_MAX && v >= DODS_LLONG_MIN) {
372 return FALSE;
373 }
374#endif
375 else {
376 return TRUE;
377 }
378}
379
380int check_uint64(const char *val) {
381 // Eat whitespace and check for an initial '-' sign...
382 // strtoul allows an initial minus. mjohnson
383 const char *c = val;
384 while (c && isspace(*c)) {
385 c++;
386 }
387 if (c && (*c == '-')) {
388 return FALSE;
389 }
390
391 char *ptr;
392 errno = 0;
393 unsigned long long v = strtoull(val, &ptr, 0);
394
395 if ((v == 0 && val == ptr) || *ptr != '\0') {
396 return FALSE;
397 }
398
399 if (errno == ERANGE) {
400 return FALSE;
401 } else if (v > DODS_ULLONG_MAX) { // 2^61
402 return FALSE;
403 } else {
404 return v;
405 }
406}
407
408// Check first for system errors (like numbers so small they convert
409// (erroneously) to zero. Then make sure that the value is within
410// limits.
411
412int check_float32(const char *val) {
413 char *ptr;
414 errno = 0; // Clear previous value. Fix for the 64bit
415 // IRIX from Rob Morris. 5/21/2001 jhrg
416
417#ifdef WIN32
418 double v = w32strtod(val, &ptr);
419#else
420 double v = strtod(val, &ptr);
421#endif
422
423 DBG(cerr << "v: " << v << ", ptr: " << ptr << ", errno: " << errno << ", val==ptr: " << (val == ptr) << endl);
424
425 if (errno == ERANGE || (v == 0.0 && val == ptr) || *ptr != '\0')
426 return FALSE;
427
428#if 0
429 if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE))
430 || *ptr != '\0') {
431 return FALSE;
432 }
433#endif
434
435 DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl);
436 double abs_val = fabs(v);
437 if (abs_val > DODS_FLT_MAX || (abs_val != 0.0 && abs_val < DODS_FLT_MIN))
438 return FALSE;
439
440 return TRUE;
441}
442
443int check_float64(const char *val) {
444 DBG(cerr << "val: " << val << endl);
445 char *ptr;
446 errno = 0; // Clear previous value. 5/21/2001 jhrg
447
448#ifdef WIN32
449 double v = w32strtod(val, &ptr);
450#else
451 double v = strtod(val, &ptr);
452#endif
453
454 DBG(cerr << "v: " << v << ", ptr: " << ptr << ", errno: " << errno << ", val==ptr: " << (val == ptr) << endl);
455
456 if (errno == ERANGE || (v == 0.0 && val == ptr) || *ptr != '\0')
457 return FALSE;
458#if 0
459 if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE))
460 || *ptr != '\0') {
461 return FALSE;
462 }
463#endif
464 DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl);
465 double abs_val = fabs(v);
466 if (abs_val > DODS_DBL_MAX || (abs_val != 0.0 && abs_val < DODS_DBL_MIN))
467 return FALSE;
468
469 return TRUE;
470}
471
472int check_float64(const char *val, double &v) {
473 DBG(cerr << "val: " << val << endl);
474 char *ptr;
475 errno = 0; // Clear previous value. 5/21/2001 jhrg
476
477#ifdef WIN32
478 v = w32strtod(val, &ptr);
479#else
480 v = strtod(val, &ptr);
481#endif
482
483 DBG(cerr << "v: " << v << ", ptr: " << ptr << ", errno: " << errno << ", val==ptr: " << (val == ptr) << endl);
484
485 if (errno == ERANGE || (v == 0.0 && val == ptr) || *ptr != '\0')
486 return FALSE;
487#if 0
488 if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE))
489 || *ptr != '\0') {
490 return FALSE;
491 }
492#endif
493 DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl);
494 double abs_val = fabs(v);
495 if (abs_val > DODS_DBL_MAX || (abs_val != 0.0 && abs_val < DODS_DBL_MIN))
496 return FALSE;
497
498 return TRUE;
499}
500
501long long get_int64(const char *val) {
502 char *ptr;
503 errno = 0;
504 long long v = strtoll(val, &ptr, 0); // `0' --> use val to determine base
505
506 if ((v == 0 && val == ptr) || *ptr != '\0') {
507 throw Error("Expected a 64-bit integer, but found other characters.");
508 // The value '" + string(val) + "' contains extra characters.");
509 }
510
511 // We need to check errno since strtol return clamps on overflow so the
512 // check against the DODS values below will always pass, even for out of
513 // bounds values in the string. mjohnson 7/20/09
514 if (errno == ERANGE) {
515 throw Error("The 64-bit integer value is out of range.");
516 }
517
518#if 0
519 // This could be combined with the above, or course, but I'm making it
520 // separate to highlight the test. On 64-bit linux boxes 'long' may be
521 // 64-bits and so 'v' can hold more than a DODS_INT32. jhrg 3/23/10
522 //
523 // Removed because coverity flags it as useless, which it is until we
524 // have 128-bit ints... jhrg 5/9/16
525 else if (v > DODS_LLONG_MAX || v < DODS_LLONG_MIN) {
526 throw Error("The value '" + string(val) + "' is out of range.");
527 }
528#endif
529
530 else {
531 return v;
532 }
533}
534
535unsigned long long get_uint64(const char *val) {
536 // Eat whitespace and check for an initial '-' sign...
537 // strtoul allows an initial minus. mjohnson
538 const char *c = val;
539 while (c && isspace(*c)) {
540 c++;
541 }
542 if (c && (*c == '-')) {
543 throw Error("Expected a valid array index.");
544 }
545
546 char *ptr;
547 errno = 0;
548 unsigned long long v = strtoull(val, &ptr, 0);
549
550 if ((v == 0 && val == ptr) || *ptr != '\0') {
551 throw Error("Expected an unsigned 64-bit integer, but found other characters.");
552 }
553
554 if (errno == ERANGE) {
555 throw Error("The 64-bit integer value is out of range.");
556 }
557#if 0
558 // Coverity; see above. jhrg 5/9/16
559 else if (v > DODS_MAX_ARRAY_INDEX) { // 2^61
560 throw Error("The value '" + string(val) + "' is out of range.");
561 }
562#endif
563 else {
564 return v;
565 }
566}
567
568int get_int32(const char *val) {
569 char *ptr;
570 errno = 0;
571 int v = strtol(val, &ptr, 0); // `0' --> use val to determine base
572
573 if ((v == 0 && val == ptr) || *ptr != '\0') {
574 throw Error("Expected a 32-bit integer, but found other characters.");
575 }
576
577 // We need to check errno since strtol return clamps on overflow so the
578 // check against the DODS values below will always pass, even for out of
579 // bounds values in the string. mjohnson 7/20/09
580 if (errno == ERANGE) {
581 throw Error("The 32-bit integer value is out of range.");
582 }
583 // This could be combined with the above, or course, but I'm making it
584 // separate to highlight the test. On 64-bit linux boxes 'long' may be
585 // 64-bits and so 'v' can hold more than a DODS_INT32. jhrg 3/23/10
586 else if (v > DODS_INT_MAX || v < DODS_INT_MIN) {
587 return FALSE;
588 }
589
590 else {
591 return v;
592 }
593}
594
595unsigned int get_uint32(const char *val) {
596 // Eat whitespace and check for an initial '-' sign...
597 // strtoul allows an initial minus. mjohnson
598 const char *c = val;
599 while (c && isspace(*c)) {
600 c++;
601 }
602 if (c && (*c == '-')) {
603 throw Error("Expected an unsigned 32-bit integer, but found other characters.");
604 }
605
606 char *ptr;
607 errno = 0;
608 unsigned int v = strtoul(val, &ptr, 0);
609
610 if ((v == 0 && val == ptr) || *ptr != '\0') {
611 throw Error("Expected an unsigned 32-bit integer, but found other characters.");
612 }
613
614 if (errno == ERANGE) {
615 throw Error("The 32-bit integer value is out of range.");
616 }
617 // See above.
618 else if (v > DODS_UINT_MAX) {
619 return FALSE;
620 } else {
621 return v;
622 }
623}
624
625double get_float64(const char *val) {
626 DBG(cerr << "val: " << val << endl);
627 char *ptr;
628 errno = 0; // Clear previous value. 5/21/2001 jhrg
629
630#ifdef WIN32
631 double v = w32strtod(val, &ptr);
632#else
633 double v = strtod(val, &ptr);
634#endif
635
636 if (errno == ERANGE || (v == 0.0 && val == ptr) || *ptr != '\0')
637 throw Error("The 64-bit floating point value is out of range.");
638 ;
639
640 DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl);
641 double abs_val = fabs(v);
642 if (abs_val > DODS_DBL_MAX || (abs_val != 0.0 && abs_val < DODS_DBL_MIN))
643 throw Error("The 64-bit floating point value is out of range.");
644 ;
645
646 return v;
647}
648
649/*
650 Maybe someday we will really check the Urls to see if they are valid...
651*/
652
653int check_url(const char *) { return TRUE; }
654
655} // namespace libdap
#define unknown_error
Unknown error (the default code) (HTTP 400)
Definition Error.h:62
#define malformed_expr
(400)
Definition Error.h:66
A class for error processing.
Definition Error.h:92
#define DBG(x)
Definition debug.h:58
#define DODS_DBL_MAX
Definition dods-limits.h:87
#define DODS_DBL_MIN
Definition dods-limits.h:89
#define DODS_SHRT_MIN
Definition dods-limits.h:68
#define DODS_UCHAR_MAX
Definition dods-limits.h:65
#define DODS_SCHAR_MIN
Definition dods-limits.h:63
#define DODS_SHRT_MAX
Definition dods-limits.h:69
#define DODS_UINT_MAX
Definition dods-limits.h:74
#define DODS_MAX_ARRAY_INDEX
Definition dods-limits.h:84
#define DODS_LLONG_MAX
Definition dods-limits.h:81
#define DODS_INT_MAX
Definition dods-limits.h:73
#define DODS_FLT_MIN
Definition dods-limits.h:93
#define DODS_INT_MIN
Definition dods-limits.h:72
#define DODS_USHRT_MAX
Definition dods-limits.h:70
#define DODS_FLT_MAX
Definition dods-limits.h:92
#define DODS_LLONG_MIN
Definition dods-limits.h:80
#define DODS_ULLONG_MAX
Definition dods-limits.h:82
int check_float64(const char *val)
int check_uint64(const char *val)
int check_url(const char *)
Is the value a valid URL?
int check_uint16(const char *val)
int check_int64(const char *val)
int check_byte(const char *val)
Is the value a valid byte?
int check_uint32(const char *val)
int check_int16(const char *val)
int check_float32(const char *val)
int check_int32(const char *val)
double get_float64(const char *val)
long long get_int64(const char *val)
unsigned int get_uint32(const char *val)
int get_int32(const char *val)
unsigned long long get_uint64(const char *val)
#define TRUE
Definition gse_parser.h:32
#define FALSE
Definition gse_parser.h:33
#define ID_MAX
Definition gse_parser.h:29
top level DAP object to house generic methods
Definition AISConnect.cc:30
string long_to_string(long val, int base)
Definition util.cc:946
string prune_spaces(const string &name)
Definition util.cc:451
void save_str(string &dst, const char *src, const int)
Save a string to a temporary variable during the parse.
void append_long_to_string(long val, int base, string &str_val)
Definition util.cc:919
void downcase(string &s)
Definition util.cc:544
void parse_error(parser_arg *arg, const char *msg, const int line_num, const char *context)
bool is_keyword(string id, const string &keyword)
Pass parameters by reference to a parser.
Definition parser.h:67
void set_error(Error *obj)
Definition parser.h:84
void set_status(int val=0)
Definition parser.h:86