Coverage Report

Created: 2026-07-14 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PROJ/src/dmstor.cpp
Line
Count
Source
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
808k
#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
7.49k
double dmstor(const char *is, char **rs) {
23
7.49k
    return dmstor_ctx(pj_get_default_ctx(), is, rs);
24
7.49k
}
25
26
808k
double dmstor_ctx(PJ_CONTEXT *ctx, const char *is, char **rs) {
27
808k
    int n, nl;
28
808k
    char *s, work[MAX_WORK];
29
808k
    const char *p;
30
808k
    double v, tv;
31
32
808k
    if (rs)
33
60.3k
        *rs = (char *)is;
34
    /* copy string into work space */
35
808k
    while (isspace(*is))
36
7
        ++is;
37
808k
    n = MAX_WORK;
38
808k
    s = work;
39
808k
    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
8.15M
    while ((isgraph(static_cast<unsigned char>(*p)) || *p == DEG_SIGN1 ||
50
809k
            *p == DEG_SIGN2) &&
51
7.35M
           --n)
52
7.35M
        *s++ = *p++;
53
808k
    *s = '\0';
54
808k
    int sign = *(s = work);
55
808k
    if (sign == '+' || sign == '-')
56
41.2k
        s++;
57
767k
    else
58
767k
        sign = '+';
59
808k
    v = 0.;
60
2.69M
    for (nl = 0; nl < 3; nl = n + 1) {
61
1.99M
        if (!(isdigit(*s) || *s == '.'))
62
103k
            break;
63
1.89M
        if ((tv = proj_strtod(s, &s)) == HUGE_VAL)
64
18
            return tv;
65
1.89M
        int adv = 1;
66
67
1.89M
        if (*s == 'D' || *s == 'd' || *s == DEG_SIGN2) {
68
            /*
69
             * Accept \xb0 as a single-byte degree symbol. This byte is the
70
             * degree symbol in various single-byte encodings: multiple ISO
71
             * 8859 parts, several Windows code pages and others.
72
             */
73
615k
            n = 0;
74
1.27M
        } else if (*s == '\'') {
75
570k
            n = 1;
76
704k
        } else if (*s == '"') {
77
526k
            n = 2;
78
526k
        } else if (s[0] == DEG_SIGN1 && s[1] == DEG_SIGN2) {
79
            /* degree symbol in UTF-8 */
80
65
            n = 0;
81
65
            adv = 2;
82
177k
        } else if (*s == 'r' || *s == 'R') {
83
228
            if (nl) {
84
0
                proj_context_errno_set(ctx,
85
0
                                       PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
86
0
                return HUGE_VAL;
87
0
            }
88
228
            ++s;
89
228
            v = tv;
90
228
            n = 4;
91
228
            continue;
92
177k
        } else {
93
177k
            v += tv * vm[nl];
94
177k
            n = 4;
95
177k
            continue;
96
177k
        }
97
98
1.71M
        if (n < nl) {
99
247
            proj_context_errno_set(ctx, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
100
247
            return HUGE_VAL;
101
247
        }
102
1.71M
        v += tv * vm[n];
103
1.71M
        s += adv;
104
1.71M
    }
105
    /* postfix sign */
106
808k
    if (*s && (p = strchr(sym, *s))) {
107
616k
        sign = (p - sym) >= 4 ? '-' : '+';
108
616k
        ++s;
109
616k
    }
110
808k
    if (sign == '-')
111
217k
        v = -v;
112
808k
    if (rs) /* return point of next char after valid string */
113
60.3k
        *rs = (char *)is + (s - work);
114
808k
    return v;
115
808k
}
116
117
static double proj_strtod(char *nptr, char **endptr)
118
119
1.89M
{
120
1.89M
    char c, *cp = nptr;
121
1.89M
    double result;
122
123
    /*
124
     * Scan for characters which cause problems with VC++ strtod()
125
     */
126
11.9M
    while ((c = *cp) != '\0') {
127
10.6M
        if (c == 'd' || c == 'D') {
128
129
            /*
130
             * Found one, so NUL it out, call strtod(),
131
             * then restore it and return
132
             */
133
614k
            *cp = '\0';
134
614k
            result = strtod(nptr, endptr);
135
614k
            *cp = c;
136
614k
            return result;
137
614k
        }
138
10.0M
        ++cp;
139
10.0M
    }
140
141
    /* no offending characters, just handle normally */
142
143
1.27M
    return pj_strtod(nptr, endptr);
144
1.89M
}