/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 |