Coverage Report

Created: 2025-06-13 06:18

/src/proj/src/dmstor.cpp
Line
Count
Source (jump to first uncovered line)
1
/* Convert DMS string to radians */
2
3
#include <ctype.h>
4
#include <math.h>
5
#include <stdlib.h>
6
#include <string.h>
7
8
#include "proj.h"
9
#include "proj_internal.h"
10
11
static double proj_strtod(char *nptr, char **endptr);
12
13
/* following should be sufficient for all but the ridiculous */
14
0
#define MAX_WORK 64
15
static const char *sym = "NnEeSsWw";
16
static const double vm[] = {DEG_TO_RAD, .0002908882086657216,
17
                            .0000048481368110953599};
18
/* byte sequence for Degree Sign U+00B0 in UTF-8. */
19
static constexpr char DEG_SIGN1 = '\xc2';
20
static constexpr char DEG_SIGN2 = '\xb0';
21
22
0
double dmstor(const char *is, char **rs) {
23
0
    return dmstor_ctx(pj_get_default_ctx(), is, rs);
24
0
}
25
26
0
double dmstor_ctx(PJ_CONTEXT *ctx, const char *is, char **rs) {
27
0
    int n, nl;
28
0
    char *s, work[MAX_WORK];
29
0
    const char *p;
30
0
    double v, tv;
31
32
0
    if (rs)
33
0
        *rs = (char *)is;
34
    /* copy string into work space */
35
0
    while (isspace(*is))
36
0
        ++is;
37
0
    n = MAX_WORK;
38
0
    s = work;
39
0
    p = (char *)is;
40
41
    /*
42
     * Copy characters into work until we hit a non-printable character or run
43
     * out of space in the buffer.  Make a special exception for the bytes of
44
     * the Degree Sign in UTF-8.
45
     *
46
     * It is possible that a really odd input (like lots of leading zeros)
47
     * could be truncated in copying into work.  But ...
48
     */
49
0
    while ((isgraph(*p) || *p == DEG_SIGN1 || *p == DEG_SIGN2) && --n)
50
0
        *s++ = *p++;
51
0
    *s = '\0';
52
0
    int sign = *(s = work);
53
0
    if (sign == '+' || sign == '-')
54
0
        s++;
55
0
    else
56
0
        sign = '+';
57
0
    v = 0.;
58
0
    for (nl = 0; nl < 3; nl = n + 1) {
59
0
        if (!(isdigit(*s) || *s == '.'))
60
0
            break;
61
0
        if ((tv = proj_strtod(s, &s)) == HUGE_VAL)
62
0
            return tv;
63
0
        int adv = 1;
64
65
0
        if (*s == 'D' || *s == 'd' || *s == DEG_SIGN2) {
66
            /*
67
             * Accept \xb0 as a single-byte degree symbol. This byte is the
68
             * degree symbol in various single-byte encodings: multiple ISO
69
             * 8859 parts, several Windows code pages and others.
70
             */
71
0
            n = 0;
72
0
        } else if (*s == '\'') {
73
0
            n = 1;
74
0
        } else if (*s == '"') {
75
0
            n = 2;
76
0
        } else if (s[0] == DEG_SIGN1 && s[1] == DEG_SIGN2) {
77
            /* degree symbol in UTF-8 */
78
0
            n = 0;
79
0
            adv = 2;
80
0
        } else if (*s == 'r' || *s == 'R') {
81
0
            if (nl) {
82
0
                proj_context_errno_set(ctx,
83
0
                                       PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
84
0
                return HUGE_VAL;
85
0
            }
86
0
            ++s;
87
0
            v = tv;
88
0
            n = 4;
89
0
            continue;
90
0
        } else {
91
0
            v += tv * vm[nl];
92
0
            n = 4;
93
0
            continue;
94
0
        }
95
96
0
        if (n < nl) {
97
0
            proj_context_errno_set(ctx, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
98
0
            return HUGE_VAL;
99
0
        }
100
0
        v += tv * vm[n];
101
0
        s += adv;
102
0
    }
103
    /* postfix sign */
104
0
    if (*s && (p = strchr(sym, *s))) {
105
0
        sign = (p - sym) >= 4 ? '-' : '+';
106
0
        ++s;
107
0
    }
108
0
    if (sign == '-')
109
0
        v = -v;
110
0
    if (rs) /* return point of next char after valid string */
111
0
        *rs = (char *)is + (s - work);
112
0
    return v;
113
0
}
114
115
static double proj_strtod(char *nptr, char **endptr)
116
117
0
{
118
0
    char c, *cp = nptr;
119
0
    double result;
120
121
    /*
122
     * Scan for characters which cause problems with VC++ strtod()
123
     */
124
0
    while ((c = *cp) != '\0') {
125
0
        if (c == 'd' || c == 'D') {
126
127
            /*
128
             * Found one, so NUL it out, call strtod(),
129
             * then restore it and return
130
             */
131
0
            *cp = '\0';
132
0
            result = strtod(nptr, endptr);
133
0
            *cp = c;
134
0
            return result;
135
0
        }
136
0
        ++cp;
137
0
    }
138
139
    /* no offending characters, just handle normally */
140
141
0
    return pj_strtod(nptr, endptr);
142
0
}