Coverage Report

Created: 2025-08-29 07:11

/src/PROJ/src/wkt1_parser.cpp
Line
Count
Source
1
/******************************************************************************
2
 * Project:  PROJ
3
 * Purpose:  WKT1 parser grammar
4
 * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
5
 *
6
 ******************************************************************************
7
 * Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a
10
 * copy of this software and associated documentation files (the "Software"),
11
 * to deal in the Software without restriction, including without limitation
12
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
 * and/or sell copies of the Software, and to permit persons to whom the
14
 * Software is furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included
17
 * in all copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25
 * DEALINGS IN THE SOFTWARE.
26
 ****************************************************************************/
27
28
#ifndef FROM_PROJ_CPP
29
#define FROM_PROJ_CPP
30
#endif
31
32
#include "proj/internal/internal.hpp"
33
34
#include <algorithm>
35
#include <cstring>
36
#include <string>
37
38
#include "wkt1_parser.h"
39
#include "wkt_parser.hpp"
40
41
using namespace NS_PROJ::internal;
42
43
//! @cond Doxygen_Suppress
44
45
// ---------------------------------------------------------------------------
46
47
struct pj_wkt1_parse_context : public pj_wkt_parse_context {};
48
49
// ---------------------------------------------------------------------------
50
51
460
void pj_wkt1_error(pj_wkt1_parse_context *context, const char *msg) {
52
460
    pj_wkt_error(context, msg);
53
460
}
54
55
// ---------------------------------------------------------------------------
56
57
753
std::string pj_wkt1_parse(const std::string &wkt) {
58
753
    pj_wkt1_parse_context context;
59
753
    context.pszInput = wkt.c_str();
60
753
    context.pszLastSuccess = wkt.c_str();
61
753
    context.pszNext = wkt.c_str();
62
753
    if (pj_wkt1_parse(&context) != 0) {
63
460
        return context.errorMsg;
64
460
    }
65
293
    return std::string();
66
753
}
67
68
// ---------------------------------------------------------------------------
69
70
typedef struct {
71
    const char *pszToken;
72
    int nTokenVal;
73
} osr_cs_wkt_tokens;
74
75
#define PAIR(X)                                                                \
76
    {                                                                          \
77
#X, T_##X                                                              \
78
    }
79
80
static const osr_cs_wkt_tokens tokens[] = {
81
    PAIR(PARAM_MT),       PAIR(PARAMETER),  PAIR(CONCAT_MT),   PAIR(INVERSE_MT),
82
    PAIR(PASSTHROUGH_MT),
83
84
    PAIR(PROJCS),         PAIR(PROJECTION), PAIR(GEOGCS),      PAIR(DATUM),
85
    PAIR(SPHEROID),       PAIR(PRIMEM),     PAIR(UNIT),        PAIR(GEOCCS),
86
    PAIR(AUTHORITY),      PAIR(VERT_CS),    PAIR(VERTCS),      PAIR(VERT_DATUM),
87
    PAIR(VDATUM),         PAIR(COMPD_CS),   PAIR(AXIS),        PAIR(TOWGS84),
88
    PAIR(FITTED_CS),      PAIR(LOCAL_CS),   PAIR(LOCAL_DATUM), PAIR(LINUNIT),
89
90
    PAIR(EXTENSION)};
91
92
// ---------------------------------------------------------------------------
93
94
24.3k
int pj_wkt1_lex(YYSTYPE * /*pNode */, pj_wkt1_parse_context *context) {
95
24.3k
    size_t i;
96
24.3k
    const char *pszInput = context->pszNext;
97
98
    /* -------------------------------------------------------------------- */
99
    /*      Skip white space.                                               */
100
    /* -------------------------------------------------------------------- */
101
24.5k
    while (*pszInput == ' ' || *pszInput == '\t' || *pszInput == 10 ||
102
24.5k
           *pszInput == 13)
103
196
        pszInput++;
104
105
24.3k
    context->pszLastSuccess = pszInput;
106
107
24.3k
    if (*pszInput == '\0') {
108
286
        context->pszNext = pszInput;
109
286
        return EOF;
110
286
    }
111
112
    /* -------------------------------------------------------------------- */
113
    /*      Recognize node names.                                           */
114
    /* -------------------------------------------------------------------- */
115
24.0k
    if (isalpha(*pszInput)) {
116
34.4k
        for (i = 0; i < sizeof(tokens) / sizeof(tokens[0]); i++) {
117
34.3k
            if (ci_starts_with(pszInput, tokens[i].pszToken) &&
118
34.3k
                !isalpha(pszInput[strlen(tokens[i].pszToken)])) {
119
4.14k
                context->pszNext = pszInput + strlen(tokens[i].pszToken);
120
4.14k
                return tokens[i].nTokenVal;
121
4.14k
            }
122
34.3k
        }
123
4.24k
    }
124
125
    /* -------------------------------------------------------------------- */
126
    /*      Recognize double quoted strings.                                */
127
    /* -------------------------------------------------------------------- */
128
19.9k
    if (*pszInput == '"') {
129
3.61k
        pszInput++;
130
51.8k
        while (*pszInput != '\0' && *pszInput != '"')
131
48.2k
            pszInput++;
132
3.61k
        if (*pszInput == '\0') {
133
5
            context->pszNext = pszInput;
134
5
            return EOF;
135
5
        }
136
3.61k
        context->pszNext = pszInput + 1;
137
3.61k
        return T_STRING;
138
3.61k
    }
139
140
    /* -------------------------------------------------------------------- */
141
    /*      Recognize numerical values.                                     */
142
    /* -------------------------------------------------------------------- */
143
144
16.3k
    if (((*pszInput == '-' || *pszInput == '+') && pszInput[1] >= '0' &&
145
16.3k
         pszInput[1] <= '9') ||
146
16.3k
        (*pszInput >= '0' && *pszInput <= '9')) {
147
2.66k
        if (*pszInput == '-' || *pszInput == '+')
148
62
            pszInput++;
149
150
        // collect non-decimal part of number
151
8.09k
        while (*pszInput >= '0' && *pszInput <= '9')
152
5.43k
            pszInput++;
153
154
        // collect decimal places.
155
2.66k
        if (*pszInput == '.') {
156
2.59k
            pszInput++;
157
11.4k
            while (*pszInput >= '0' && *pszInput <= '9')
158
8.81k
                pszInput++;
159
2.59k
        }
160
161
        // collect exponent
162
2.66k
        if (*pszInput == 'e' || *pszInput == 'E') {
163
9
            pszInput++;
164
9
            if (*pszInput == '-' || *pszInput == '+')
165
1
                pszInput++;
166
27
            while (*pszInput >= '0' && *pszInput <= '9')
167
18
                pszInput++;
168
9
        }
169
170
2.66k
        context->pszNext = pszInput;
171
172
2.66k
        return T_NUMBER;
173
2.66k
    }
174
175
    /* -------------------------------------------------------------------- */
176
    /*      Recognize identifiers.                                          */
177
    /* -------------------------------------------------------------------- */
178
13.6k
    if ((*pszInput >= 'A' && *pszInput <= 'Z') ||
179
13.6k
        (*pszInput >= 'a' && *pszInput <= 'z')) {
180
100
        pszInput++;
181
520
        while ((*pszInput >= 'A' && *pszInput <= 'Z') ||
182
520
               (*pszInput >= 'a' && *pszInput <= 'z'))
183
420
            pszInput++;
184
100
        context->pszNext = pszInput;
185
100
        return T_IDENTIFIER;
186
100
    }
187
188
    /* -------------------------------------------------------------------- */
189
    /*      Handle special tokens.                                          */
190
    /* -------------------------------------------------------------------- */
191
13.5k
    context->pszNext = pszInput + 1;
192
13.5k
    return *pszInput;
193
13.6k
}
194
195
//! @endcond