Coverage Report

Created: 2026-09-01 06:55

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
703k
#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
6.16k
double dmstor(const char *is, char **rs) {
23
6.16k
    return dmstor_ctx(pj_get_default_ctx(), is, rs);
24
6.16k
}
25
26
703k
double dmstor_ctx(PJ_CONTEXT *ctx, const char *is, char **rs) {
27
703k
    int n, nl;
28
703k
    char *s, work[MAX_WORK];
29
703k
    const char *p;
30
703k
    double v, tv;
31
32
703k
    if (rs)
33
43.9k
        *rs = (char *)is;
34
    /* copy string into work space */
35
703k
    while (isspace(*is))
36
7
        ++is;
37
703k
    n = MAX_WORK;
38
703k
    s = work;
39
703k
    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
7.32M
    while ((isgraph(static_cast<unsigned char>(*p)) || *p == DEG_SIGN1 ||
50
704k
            *p == DEG_SIGN2) &&
51
6.61M
           --n)
52
6.61M
        *s++ = *p++;
53
703k
    *s = '\0';
54
703k
    int sign = *(s = work);
55
703k
    if (sign == '+' || sign == '-')
56
35.7k
        s++;
57
667k
    else
58
667k
        sign = '+';
59
703k
    v = 0.;
60
2.39M
    for (nl = 0; nl < 3; nl = n + 1) {
61
1.78M
        if (!(isdigit(*s) || *s == '.'))
62
92.3k
            break;
63
1.69M
        if ((tv = proj_strtod(s, &s)) == HUGE_VAL)
64
12
            return tv;
65
1.69M
        int adv = 1;
66
67
1.69M
        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
562k
            n = 0;
74
1.13M
        } else if (*s == '\'') {
75
521k
            n = 1;
76
610k
        } else if (*s == '"') {
77
481k
            n = 2;
78
481k
        } else if (s[0] == DEG_SIGN1 && s[1] == DEG_SIGN2) {
79
            /* degree symbol in UTF-8 */
80
64
            n = 0;
81
64
            adv = 2;
82
129k
        } else if (*s == 'r' || *s == 'R') {
83
167
            if (nl) {
84
1
                proj_context_errno_set(ctx,
85
1
                                       PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
86
1
                return HUGE_VAL;
87
1
            }
88
166
            ++s;
89
166
            v = tv;
90
166
            n = 4;
91
166
            continue;
92
129k
        } else {
93
129k
            v += tv * vm[nl];
94
129k
            n = 4;
95
129k
            continue;
96
129k
        }
97
98
1.56M
        if (n < nl) {
99
267
            proj_context_errno_set(ctx, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
100
267
            return HUGE_VAL;
101
267
        }
102
1.56M
        v += tv * vm[n];
103
1.56M
        s += adv;
104
1.56M
    }
105
    /* postfix sign */
106
702k
    if (*s && (p = strchr(sym, *s))) {
107
563k
        sign = (p - sym) >= 4 ? '-' : '+';
108
563k
        ++s;
109
563k
    }
110
702k
    if (sign == '-')
111
196k
        v = -v;
112
702k
    if (rs) /* return point of next char after valid string */
113
43.9k
        *rs = (char *)is + (s - work);
114
702k
    return v;
115
703k
}
116
117
static double proj_strtod(char *nptr, char **endptr)
118
119
1.69M
{
120
1.69M
    char c, *cp = nptr;
121
1.69M
    double result;
122
123
    /*
124
     * Scan for characters which cause problems with VC++ strtod()
125
     */
126
10.8M
    while ((c = *cp) != '\0') {
127
9.69M
        if (c == 'd' || c == 'D') {
128
129
            /*
130
             * Found one, so NUL it out, call strtod(),
131
             * then restore it and return
132
             */
133
561k
            *cp = '\0';
134
561k
            result = strtod(nptr, endptr);
135
561k
            *cp = c;
136
561k
            return result;
137
561k
        }
138
9.12M
        ++cp;
139
9.12M
    }
140
141
    /* no offending characters, just handle normally */
142
143
1.13M
    return pj_strtod(nptr, endptr);
144
1.69M
}