Coverage Report

Created: 2025-06-13 06:18

/src/proj/src/wkt2_parser.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 * Project:  PROJ
3
 * Purpose:  WKT2 parser grammar
4
 * Author:   Even Rouault, <even.rouault at spatialys.com>
5
 *
6
 ******************************************************************************
7
 * Copyright (c) 2018 Even Rouault, <even.rouault at spatialys.com>
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 <cctype>
36
#include <cstring>
37
#include <string>
38
39
#include "proj_constants.h"
40
#include "wkt2_parser.h"
41
#include "wkt_parser.hpp"
42
43
using namespace NS_PROJ::internal;
44
45
//! @cond Doxygen_Suppress
46
47
// ---------------------------------------------------------------------------
48
49
struct pj_wkt2_parse_context : public pj_wkt_parse_context {};
50
51
// ---------------------------------------------------------------------------
52
53
0
void pj_wkt2_error(pj_wkt2_parse_context *context, const char *msg) {
54
0
    pj_wkt_error(context, msg);
55
0
}
56
57
// ---------------------------------------------------------------------------
58
59
0
std::string pj_wkt2_parse(const std::string &wkt) {
60
0
    pj_wkt2_parse_context context;
61
0
    context.pszInput = wkt.c_str();
62
0
    context.pszLastSuccess = wkt.c_str();
63
0
    context.pszNext = wkt.c_str();
64
0
    if (pj_wkt2_parse(&context) != 0) {
65
0
        return context.errorMsg;
66
0
    }
67
0
    return std::string();
68
0
}
69
70
// ---------------------------------------------------------------------------
71
72
typedef struct {
73
    const char *pszToken;
74
    int nTokenVal;
75
} wkt2_tokens;
76
77
#define PAIR(X)                                                                \
78
    {                                                                          \
79
#X, T_##X                                                              \
80
    }
81
82
static const wkt2_tokens tokens[] = {
83
    PAIR(PARAMETER),
84
    PAIR(PROJECTION),
85
    PAIR(DATUM),
86
    PAIR(SPHEROID),
87
    PAIR(PRIMEM),
88
    PAIR(UNIT),
89
    PAIR(AXIS),
90
91
    PAIR(GEODCRS),
92
    PAIR(LENGTHUNIT),
93
    PAIR(ANGLEUNIT),
94
    PAIR(SCALEUNIT),
95
    PAIR(TIMEUNIT),
96
    PAIR(ELLIPSOID),
97
    PAIR(CS),
98
    PAIR(ID),
99
    PAIR(PROJCRS),
100
    PAIR(BASEGEODCRS),
101
    PAIR(MERIDIAN),
102
    PAIR(BEARING),
103
    PAIR(ORDER),
104
    PAIR(ANCHOR),
105
    PAIR(ANCHOREPOCH),
106
    PAIR(CONVERSION),
107
    PAIR(METHOD),
108
    PAIR(REMARK),
109
    PAIR(GEOGCRS),
110
    PAIR(BASEGEOGCRS),
111
    PAIR(SCOPE),
112
    PAIR(AREA),
113
    PAIR(BBOX),
114
    PAIR(CITATION),
115
    PAIR(URI),
116
    PAIR(VERTCRS),
117
    PAIR(VDATUM),
118
    PAIR(GEOIDMODEL),
119
    PAIR(COMPOUNDCRS),
120
    PAIR(PARAMETERFILE),
121
    PAIR(COORDINATEOPERATION),
122
    PAIR(SOURCECRS),
123
    PAIR(TARGETCRS),
124
    PAIR(INTERPOLATIONCRS),
125
    PAIR(OPERATIONACCURACY),
126
    PAIR(CONCATENATEDOPERATION),
127
    PAIR(STEP),
128
    PAIR(BOUNDCRS),
129
    PAIR(ABRIDGEDTRANSFORMATION),
130
    PAIR(DERIVINGCONVERSION),
131
    PAIR(TDATUM),
132
    PAIR(CALENDAR),
133
    PAIR(TIMEORIGIN),
134
    PAIR(TIMECRS),
135
    PAIR(VERTICALEXTENT),
136
    PAIR(TIMEEXTENT),
137
    PAIR(USAGE),
138
    PAIR(DYNAMIC),
139
    PAIR(FRAMEEPOCH),
140
    PAIR(MODEL),
141
    PAIR(VELOCITYGRID),
142
    PAIR(ENSEMBLE),
143
    PAIR(MEMBER),
144
    PAIR(ENSEMBLEACCURACY),
145
    PAIR(DERIVEDPROJCRS),
146
    PAIR(BASEPROJCRS),
147
    PAIR(EDATUM),
148
    PAIR(ENGCRS),
149
    PAIR(PDATUM),
150
    PAIR(PARAMETRICCRS),
151
    PAIR(PARAMETRICUNIT),
152
    PAIR(BASEVERTCRS),
153
    PAIR(BASEENGCRS),
154
    PAIR(BASEPARAMCRS),
155
    PAIR(BASETIMECRS),
156
    PAIR(GEODETICCRS),
157
    PAIR(GEODETICDATUM),
158
    PAIR(PROJECTEDCRS),
159
    PAIR(PRIMEMERIDIAN),
160
    PAIR(GEOGRAPHICCRS),
161
    PAIR(TRF),
162
    PAIR(VERTICALCRS),
163
    PAIR(VERTICALDATUM),
164
    PAIR(VRF),
165
    PAIR(TIMEDATUM),
166
    PAIR(TEMPORALQUANTITY),
167
    PAIR(ENGINEERINGDATUM),
168
    PAIR(ENGINEERINGCRS),
169
    PAIR(PARAMETRICDATUM),
170
    PAIR(EPOCH),
171
    PAIR(COORDEPOCH),
172
    PAIR(COORDINATEMETADATA),
173
    PAIR(POINTMOTIONOPERATION),
174
    PAIR(VERSION),
175
    PAIR(AXISMINVALUE),
176
    PAIR(AXISMAXVALUE),
177
    PAIR(RANGEMEANING),
178
    PAIR(exact),
179
    PAIR(wraparound),
180
    PAIR(DEFININGTRANSFORMATION),
181
182
    // CS types
183
    PAIR(AFFINE),
184
    PAIR(CARTESIAN),
185
    PAIR(CYLINDRICAL),
186
    PAIR(ELLIPSOIDAL),
187
    PAIR(LINEAR),
188
    PAIR(PARAMETRIC),
189
    PAIR(POLAR),
190
    PAIR(SPHERICAL),
191
    PAIR(VERTICAL),
192
    PAIR(TEMPORAL),
193
    PAIR(TEMPORALCOUNT),
194
    PAIR(TEMPORALMEASURE),
195
    PAIR(ORDINAL),
196
    PAIR(TEMPORALDATETIME),
197
198
    // Axis directions
199
    PAIR(NORTH),
200
    PAIR(NORTHNORTHEAST),
201
    PAIR(NORTHEAST),
202
    PAIR(EASTNORTHEAST),
203
    PAIR(EAST),
204
    PAIR(EASTSOUTHEAST),
205
    PAIR(SOUTHEAST),
206
    PAIR(SOUTHSOUTHEAST),
207
    PAIR(SOUTH),
208
    PAIR(SOUTHSOUTHWEST),
209
    PAIR(SOUTHWEST),
210
    PAIR(WESTSOUTHWEST),
211
    PAIR(WEST),
212
    PAIR(WESTNORTHWEST),
213
    PAIR(NORTHWEST),
214
    PAIR(NORTHNORTHWEST),
215
    PAIR(UP),
216
    PAIR(DOWN),
217
    PAIR(GEOCENTRICX),
218
    PAIR(GEOCENTRICY),
219
    PAIR(GEOCENTRICZ),
220
    PAIR(COLUMNPOSITIVE),
221
    PAIR(COLUMNNEGATIVE),
222
    PAIR(ROWPOSITIVE),
223
    PAIR(ROWNEGATIVE),
224
    PAIR(DISPLAYRIGHT),
225
    PAIR(DISPLAYLEFT),
226
    PAIR(DISPLAYUP),
227
    PAIR(DISPLAYDOWN),
228
    PAIR(FORWARD),
229
    PAIR(AFT),
230
    PAIR(PORT),
231
    PAIR(STARBOARD),
232
    PAIR(CLOCKWISE),
233
    PAIR(COUNTERCLOCKWISE),
234
    PAIR(TOWARDS),
235
    PAIR(AWAYFROM),
236
    PAIR(FUTURE),
237
    PAIR(PAST),
238
    PAIR(UNSPECIFIED),
239
};
240
241
// ---------------------------------------------------------------------------
242
243
0
int pj_wkt2_lex(YYSTYPE * /*pNode */, pj_wkt2_parse_context *context) {
244
0
    size_t i;
245
0
    const char *pszInput = context->pszNext;
246
247
    /* -------------------------------------------------------------------- */
248
    /*      Skip white space.                                               */
249
    /* -------------------------------------------------------------------- */
250
0
    while (*pszInput == ' ' || *pszInput == '\t' || *pszInput == 10 ||
251
0
           *pszInput == 13)
252
0
        pszInput++;
253
254
0
    context->pszLastSuccess = pszInput;
255
256
0
    if (*pszInput == '\0') {
257
0
        context->pszNext = pszInput;
258
0
        return EOF;
259
0
    }
260
261
    /* -------------------------------------------------------------------- */
262
    /*      Recognize node names.                                           */
263
    /* -------------------------------------------------------------------- */
264
0
    if (isalpha(*pszInput)) {
265
0
        for (i = 0; i < sizeof(tokens) / sizeof(tokens[0]); i++) {
266
0
            if (ci_starts_with(pszInput, tokens[i].pszToken) &&
267
0
                !isalpha(pszInput[strlen(tokens[i].pszToken)])) {
268
0
                context->pszNext = pszInput + strlen(tokens[i].pszToken);
269
0
                return tokens[i].nTokenVal;
270
0
            }
271
0
        }
272
0
    }
273
274
    /* -------------------------------------------------------------------- */
275
    /*      Recognize unsigned integer                                      */
276
    /* -------------------------------------------------------------------- */
277
278
0
    if (*pszInput >= '0' && *pszInput <= '9') {
279
280
        // Special case for 1, 2, 3
281
0
        if ((*pszInput == '1' || *pszInput == '2' || *pszInput == '3') &&
282
0
            !(pszInput[1] >= '0' && pszInput[1] <= '9')) {
283
0
            context->pszNext = pszInput + 1;
284
0
            return *pszInput;
285
0
        }
286
287
0
        pszInput++;
288
0
        while (*pszInput >= '0' && *pszInput <= '9')
289
0
            pszInput++;
290
291
0
        context->pszNext = pszInput;
292
293
0
        return T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE;
294
0
    }
295
296
    /* -------------------------------------------------------------------- */
297
    /*      Recognize double quoted strings.                                */
298
    /* -------------------------------------------------------------------- */
299
0
    if (*pszInput == '"') {
300
0
        pszInput++;
301
0
        while (*pszInput != '\0') {
302
0
            if (*pszInput == '"') {
303
0
                if (pszInput[1] == '"')
304
0
                    pszInput++;
305
0
                else
306
0
                    break;
307
0
            }
308
0
            pszInput++;
309
0
        }
310
0
        if (*pszInput == '\0') {
311
0
            context->pszNext = pszInput;
312
0
            return EOF;
313
0
        }
314
0
        context->pszNext = pszInput + 1;
315
0
        return T_STRING;
316
0
    }
317
318
    // As used in examples of OGC 12-063r5
319
0
    const char *startPrintedQuote = "\xE2\x80\x9C";
320
0
    const char *endPrintedQuote = "\xE2\x80\x9D";
321
0
    if (strncmp(pszInput, startPrintedQuote, 3) == 0) {
322
0
        context->pszNext = strstr(pszInput, endPrintedQuote);
323
0
        if (context->pszNext == nullptr) {
324
0
            context->pszNext = pszInput + strlen(pszInput);
325
0
            return EOF;
326
0
        }
327
0
        context->pszNext += 3;
328
0
        return T_STRING;
329
0
    }
330
331
    /* -------------------------------------------------------------------- */
332
    /*      Handle special tokens.                                          */
333
    /* -------------------------------------------------------------------- */
334
0
    context->pszNext = pszInput + 1;
335
0
    return *pszInput;
336
0
}
337
338
//! @endcond