/src/postgis/liblwgeom/lwin_wkb.c
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * PostGIS - Spatial Types for PostgreSQL |
4 | | * http://postgis.net |
5 | | * |
6 | | * PostGIS is free software: you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation, either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * PostGIS is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with PostGIS. If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | ********************************************************************** |
20 | | * |
21 | | * Copyright (C) 2009 Paul Ramsey <pramsey@cleverelephant.ca> |
22 | | * |
23 | | **********************************************************************/ |
24 | | |
25 | | |
26 | | #include "../postgis_config.h" |
27 | | /*#define POSTGIS_DEBUG_LEVEL 4*/ |
28 | | #include "liblwgeom_internal.h" /* NOTE: includes lwgeom_log.h */ |
29 | | #include "lwgeom_log.h" |
30 | | #include <math.h> |
31 | | #include <limits.h> |
32 | | |
33 | | /** Max depth in a geometry. Matches the default YYINITDEPTH for WKT */ |
34 | 0 | #define LW_PARSER_MAX_DEPTH 200 |
35 | | |
36 | | /** |
37 | | * Used for passing the parse state between the parsing functions. |
38 | | */ |
39 | | typedef struct |
40 | | { |
41 | | const uint8_t *wkb; /* Points to start of WKB */ |
42 | | int32_t srid; /* Current SRID we are handling */ |
43 | | size_t wkb_size; /* Expected size of WKB */ |
44 | | int8_t swap_bytes; /* Do an endian flip? */ |
45 | | int8_t check; /* Simple validity checks on geometries */ |
46 | | int8_t lwtype; /* Current type we are handling */ |
47 | | int8_t has_z; /* Z? */ |
48 | | int8_t has_m; /* M? */ |
49 | | int8_t has_srid; /* SRID? */ |
50 | | int8_t error; /* An error was found (not enough bytes to read) */ |
51 | | uint8_t depth; /* Current recursion level (to prevent stack overflows). Maxes at LW_PARSER_MAX_DEPTH */ |
52 | | const uint8_t *pos; /* Current parse position */ |
53 | | } wkb_parse_state; |
54 | | |
55 | | |
56 | | /** |
57 | | * Internal function declarations. |
58 | | */ |
59 | | LWGEOM* lwgeom_from_wkb_state(wkb_parse_state *s); |
60 | | |
61 | | |
62 | | |
63 | | /**********************************************************************/ |
64 | | |
65 | | /* Our static character->number map. Anything > 15 is invalid */ |
66 | | static uint8_t hex2char[256] = { |
67 | | /* not Hex characters */ |
68 | | 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, |
69 | | 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, |
70 | | 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, |
71 | | /* 0-9 */ |
72 | | 0,1,2,3,4,5,6,7,8,9,20,20,20,20,20,20, |
73 | | /* A-F */ |
74 | | 20,10,11,12,13,14,15,20,20,20,20,20,20,20,20,20, |
75 | | /* not Hex characters */ |
76 | | 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, |
77 | | /* a-f */ |
78 | | 20,10,11,12,13,14,15,20,20,20,20,20,20,20,20,20, |
79 | | 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, |
80 | | /* not Hex characters (upper 128 characters) */ |
81 | | 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, |
82 | | 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, |
83 | | 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, |
84 | | 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, |
85 | | 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, |
86 | | 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, |
87 | | 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, |
88 | | 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20 |
89 | | }; |
90 | | |
91 | | |
92 | | uint8_t* bytes_from_hexbytes(const char *hexbuf, size_t hexsize) |
93 | 0 | { |
94 | 0 | uint8_t *buf = NULL; |
95 | 0 | register uint8_t h1, h2; |
96 | 0 | uint32_t i; |
97 | |
|
98 | 0 | if( hexsize % 2 ) |
99 | 0 | lwerror("Invalid hex string, length (%zu) has to be a multiple of two!", hexsize); |
100 | |
|
101 | 0 | buf = lwalloc(hexsize/2); |
102 | |
|
103 | 0 | if( ! buf ) |
104 | 0 | lwerror("Unable to allocate memory buffer."); |
105 | |
|
106 | 0 | for( i = 0; i < hexsize/2; i++ ) |
107 | 0 | { |
108 | 0 | h1 = hex2char[(uint8_t)hexbuf[2*i]]; |
109 | 0 | h2 = hex2char[(uint8_t)hexbuf[2*i+1]]; |
110 | 0 | if( h1 > 15 ) |
111 | 0 | lwerror("Invalid hex character (%c) encountered", hexbuf[2*i]); |
112 | 0 | if( h2 > 15 ) |
113 | 0 | lwerror("Invalid hex character (%c) encountered", hexbuf[2*i+1]); |
114 | | /* First character is high bits, second is low bits */ |
115 | 0 | buf[i] = ((h1 & 0x0F) << 4) | (h2 & 0x0F); |
116 | 0 | } |
117 | 0 | return buf; |
118 | 0 | } |
119 | | |
120 | | |
121 | | /**********************************************************************/ |
122 | | |
123 | | |
124 | | |
125 | | /** |
126 | | * Check that we are not about to read off the end of the WKB |
127 | | * array. |
128 | | */ |
129 | | static inline void wkb_parse_state_check(wkb_parse_state *s, size_t next) |
130 | 0 | { |
131 | 0 | if( (s->pos + next) > (s->wkb + s->wkb_size) ) |
132 | 0 | { |
133 | 0 | lwerror("WKB structure does not match expected size!"); |
134 | 0 | s->error = LW_TRUE; |
135 | 0 | } |
136 | 0 | } |
137 | | |
138 | | /** |
139 | | * Resolve a raw WKB type number into the parser state' internal type and flags. |
140 | | * |
141 | | * Interprets WKB type encodings (including extended flag bits and ISO-style |
142 | | * 1000/2000/3000 modifiers) and updates the provided parse state: |
143 | | * - sets s->has_z, s->has_m, s->has_srid according to detected flags, |
144 | | * - sets s->lwtype to the corresponding internal lwgeom type enum. |
145 | | * |
146 | | * Recognizes standard WKB types, ISO extended encodings (where 1000/2000/3000 |
147 | | * ranges indicate Z/M presence), explicit high-bit flag encodings, and a few |
148 | | * legacy PostGIS values (e.g., old Curve/Surface codes). On unrecognized or |
149 | | * out-of-range type numbers an error is reported via lwerror and the state is |
150 | | * left with whatever values were set before the error. |
151 | | */ |
152 | | static void lwtype_from_wkb_state(wkb_parse_state *s, uint32_t wkb_type) |
153 | 0 | { |
154 | 0 | uint32_t wkb_simple_type; |
155 | |
|
156 | 0 | LWDEBUG(4, "Entered function"); |
157 | |
|
158 | 0 | s->has_z = LW_FALSE; |
159 | 0 | s->has_m = LW_FALSE; |
160 | 0 | s->has_srid = LW_FALSE; |
161 | | |
162 | | /* If any of the higher bits are set, this is probably an extended type. */ |
163 | 0 | if( wkb_type & 0xF0000000 ) |
164 | 0 | { |
165 | 0 | if( wkb_type & WKBZOFFSET ) s->has_z = LW_TRUE; |
166 | 0 | if( wkb_type & WKBMOFFSET ) s->has_m = LW_TRUE; |
167 | 0 | if( wkb_type & WKBSRIDFLAG ) s->has_srid = LW_TRUE; |
168 | 0 | LWDEBUGF(4, "Extended type: has_z=%d has_m=%d has_srid=%d", s->has_z, s->has_m, s->has_srid); |
169 | 0 | } |
170 | | |
171 | | /* Mask off the flags */ |
172 | 0 | wkb_type = wkb_type & 0x0FFFFFFF; |
173 | | |
174 | | /* Catch strange Oracle WKB type numbers */ |
175 | 0 | if ( wkb_type >= 4000 ) { |
176 | 0 | lwerror("Unknown WKB type (%d)!", wkb_type); |
177 | 0 | return; |
178 | 0 | } |
179 | | |
180 | | /* Strip out just the type number (1-12) from the ISO number (eg 3001-3012) */ |
181 | 0 | wkb_simple_type = wkb_type % 1000; |
182 | | |
183 | | /* Extract the Z/M information from ISO style numbers */ |
184 | 0 | if( wkb_type >= 3000 && wkb_type < 4000 ) |
185 | 0 | { |
186 | 0 | s->has_z = LW_TRUE; |
187 | 0 | s->has_m = LW_TRUE; |
188 | 0 | } |
189 | 0 | else if ( wkb_type >= 2000 && wkb_type < 3000 ) |
190 | 0 | { |
191 | 0 | s->has_m = LW_TRUE; |
192 | 0 | } |
193 | 0 | else if ( wkb_type >= 1000 && wkb_type < 2000 ) |
194 | 0 | { |
195 | 0 | s->has_z = LW_TRUE; |
196 | 0 | } |
197 | |
|
198 | 0 | switch (wkb_simple_type) |
199 | 0 | { |
200 | 0 | case WKB_POINT_TYPE: |
201 | 0 | s->lwtype = POINTTYPE; |
202 | 0 | break; |
203 | 0 | case WKB_LINESTRING_TYPE: |
204 | 0 | s->lwtype = LINETYPE; |
205 | 0 | break; |
206 | 0 | case WKB_POLYGON_TYPE: |
207 | 0 | s->lwtype = POLYGONTYPE; |
208 | 0 | break; |
209 | 0 | case WKB_MULTIPOINT_TYPE: |
210 | 0 | s->lwtype = MULTIPOINTTYPE; |
211 | 0 | break; |
212 | 0 | case WKB_MULTILINESTRING_TYPE: |
213 | 0 | s->lwtype = MULTILINETYPE; |
214 | 0 | break; |
215 | 0 | case WKB_MULTIPOLYGON_TYPE: |
216 | 0 | s->lwtype = MULTIPOLYGONTYPE; |
217 | 0 | break; |
218 | 0 | case WKB_GEOMETRYCOLLECTION_TYPE: |
219 | 0 | s->lwtype = COLLECTIONTYPE; |
220 | 0 | break; |
221 | 0 | case WKB_CIRCULARSTRING_TYPE: |
222 | 0 | s->lwtype = CIRCSTRINGTYPE; |
223 | 0 | break; |
224 | 0 | case WKB_COMPOUNDCURVE_TYPE: |
225 | 0 | s->lwtype = COMPOUNDTYPE; |
226 | 0 | break; |
227 | 0 | case WKB_CURVEPOLYGON_TYPE: |
228 | 0 | s->lwtype = CURVEPOLYTYPE; |
229 | 0 | break; |
230 | 0 | case WKB_MULTICURVE_TYPE: |
231 | 0 | s->lwtype = MULTICURVETYPE; |
232 | 0 | break; |
233 | 0 | case WKB_MULTISURFACE_TYPE: |
234 | 0 | s->lwtype = MULTISURFACETYPE; |
235 | 0 | break; |
236 | 0 | case WKB_POLYHEDRALSURFACE_TYPE: |
237 | 0 | s->lwtype = POLYHEDRALSURFACETYPE; |
238 | 0 | break; |
239 | 0 | case WKB_TIN_TYPE: |
240 | 0 | s->lwtype = TINTYPE; |
241 | 0 | break; |
242 | 0 | case WKB_TRIANGLE_TYPE: |
243 | 0 | s->lwtype = TRIANGLETYPE; |
244 | 0 | break; |
245 | 0 | case WKB_NURBSCURVE_TYPE: |
246 | 0 | s->lwtype = NURBSCURVETYPE; |
247 | 0 | break; |
248 | | |
249 | | /* PostGIS 1.5 emits 13, 14 for CurvePolygon, MultiCurve */ |
250 | | /* These numbers aren't SQL/MM (numbers currently only */ |
251 | | /* go up to 12. We can handle the old data here (for now??) */ |
252 | | /* converting them into the lwtypes that are intended. */ |
253 | 0 | case WKB_CURVE_TYPE: |
254 | 0 | s->lwtype = CURVEPOLYTYPE; |
255 | 0 | break; |
256 | 0 | case WKB_SURFACE_TYPE: |
257 | 0 | s->lwtype = MULTICURVETYPE; |
258 | 0 | break; |
259 | | |
260 | 0 | default: /* Error! */ |
261 | 0 | lwerror("Unknown WKB type (%d)! Full WKB type number was (%d).", wkb_simple_type, wkb_type); |
262 | 0 | break; |
263 | 0 | } |
264 | | |
265 | 0 | LWDEBUGF(4,"Got lwtype %s (%u)", lwtype_name(s->lwtype), s->lwtype); |
266 | |
|
267 | 0 | return; |
268 | 0 | } |
269 | | |
270 | | /** |
271 | | * Byte |
272 | | * Read a byte and advance the parse state forward. |
273 | | */ |
274 | | static char byte_from_wkb_state(wkb_parse_state *s) |
275 | 0 | { |
276 | 0 | char char_value = 0; |
277 | 0 | LWDEBUG(4, "Entered function"); |
278 | |
|
279 | 0 | wkb_parse_state_check(s, WKB_BYTE_SIZE); |
280 | 0 | if (s->error) |
281 | 0 | return 0; |
282 | 0 | LWDEBUG(4, "Passed state check"); |
283 | |
|
284 | 0 | char_value = s->pos[0]; |
285 | 0 | LWDEBUGF(4, "Read byte value: %x", char_value); |
286 | 0 | s->pos += WKB_BYTE_SIZE; |
287 | |
|
288 | 0 | return char_value; |
289 | 0 | } |
290 | | |
291 | | |
292 | | /** |
293 | | * Int32 |
294 | | * Read 4-byte integer and advance the parse state forward. |
295 | | */ |
296 | | static uint32_t integer_from_wkb_state(wkb_parse_state *s) |
297 | 0 | { |
298 | 0 | uint32_t i = 0; |
299 | |
|
300 | 0 | wkb_parse_state_check(s, WKB_INT_SIZE); |
301 | 0 | if (s->error) |
302 | 0 | return 0; |
303 | | |
304 | 0 | memcpy(&i, s->pos, WKB_INT_SIZE); |
305 | | |
306 | | /* Swap? Copy into a stack-allocated integer. */ |
307 | 0 | if( s->swap_bytes ) |
308 | 0 | { |
309 | 0 | int j = 0; |
310 | 0 | uint8_t tmp; |
311 | |
|
312 | 0 | for( j = 0; j < WKB_INT_SIZE/2; j++ ) |
313 | 0 | { |
314 | 0 | tmp = ((uint8_t*)(&i))[j]; |
315 | 0 | ((uint8_t*)(&i))[j] = ((uint8_t*)(&i))[WKB_INT_SIZE - j - 1]; |
316 | 0 | ((uint8_t*)(&i))[WKB_INT_SIZE - j - 1] = tmp; |
317 | 0 | } |
318 | 0 | } |
319 | |
|
320 | 0 | s->pos += WKB_INT_SIZE; |
321 | 0 | return i; |
322 | 0 | } |
323 | | |
324 | | /** |
325 | | * Double |
326 | | * Read an 8-byte double and advance the parse state forward. |
327 | | */ |
328 | | static double double_from_wkb_state(wkb_parse_state *s) |
329 | 0 | { |
330 | 0 | double d = 0; |
331 | | |
332 | | /* Check bounds before reading */ |
333 | 0 | wkb_parse_state_check(s, WKB_DOUBLE_SIZE); |
334 | 0 | if (s->error) return 0.0; |
335 | | |
336 | 0 | memcpy(&d, s->pos, WKB_DOUBLE_SIZE); |
337 | | |
338 | | /* Swap? Copy into a stack-allocated integer. */ |
339 | 0 | if( s->swap_bytes ) |
340 | 0 | { |
341 | 0 | int i = 0; |
342 | 0 | uint8_t tmp; |
343 | |
|
344 | 0 | for( i = 0; i < WKB_DOUBLE_SIZE/2; i++ ) |
345 | 0 | { |
346 | 0 | tmp = ((uint8_t*)(&d))[i]; |
347 | 0 | ((uint8_t*)(&d))[i] = ((uint8_t*)(&d))[WKB_DOUBLE_SIZE - i - 1]; |
348 | 0 | ((uint8_t*)(&d))[WKB_DOUBLE_SIZE - i - 1] = tmp; |
349 | 0 | } |
350 | 0 | } |
351 | |
|
352 | 0 | s->pos += WKB_DOUBLE_SIZE; |
353 | 0 | return d; |
354 | 0 | } |
355 | | |
356 | | |
357 | | |
358 | | /** |
359 | | * Set the swap bytes flag depending on the endianness |
360 | | * of the machine and the endianness of the input data. |
361 | | * If they differ, we must swap, otherwise we can copy. |
362 | | */ |
363 | | static void wkb_swap_bytes(wkb_parse_state *s) |
364 | 0 | { |
365 | 0 | char wkb_little_endian; |
366 | | |
367 | | /* Fail when handed incorrect starting byte */ |
368 | 0 | wkb_little_endian = byte_from_wkb_state(s); |
369 | 0 | if (s->error) |
370 | 0 | lwerror("Invalid endian flag value encountered."); |
371 | |
|
372 | 0 | if( wkb_little_endian != 1 && wkb_little_endian != 0 ) |
373 | 0 | lwerror("Invalid endian flag value encountered."); |
374 | | |
375 | | /* Check the endianness of our input */ |
376 | 0 | s->swap_bytes = LW_FALSE; |
377 | | |
378 | | /* Machine arch is big endian, request is for little */ |
379 | 0 | if (IS_BIG_ENDIAN && wkb_little_endian) |
380 | 0 | s->swap_bytes = LW_TRUE; |
381 | | /* Machine arch is little endian, request is for big */ |
382 | 0 | else if ((!IS_BIG_ENDIAN) && (!wkb_little_endian)) |
383 | 0 | s->swap_bytes = LW_TRUE; |
384 | 0 | } |
385 | | |
386 | | |
387 | | |
388 | | /** |
389 | | * POINTARRAY |
390 | | * Read a dynamically sized point array and advance the parse state forward. |
391 | | * First read the number of points, then read the points. |
392 | | */ |
393 | | static POINTARRAY* ptarray_from_wkb_state(wkb_parse_state *s) |
394 | 0 | { |
395 | 0 | POINTARRAY *pa = NULL; |
396 | 0 | size_t pa_size; |
397 | 0 | uint32_t npoints = 0; |
398 | 0 | static uint32_t maxpoints = UINT_MAX / WKB_DOUBLE_SIZE / 4; |
399 | 0 | uint32_t ndims = 2 + s->has_z + s->has_m; |
400 | | |
401 | | /* Calculate the size of this point array. */ |
402 | 0 | npoints = integer_from_wkb_state(s); |
403 | 0 | if (s->error) |
404 | 0 | return NULL; |
405 | | |
406 | 0 | if (npoints > maxpoints) |
407 | 0 | { |
408 | 0 | s->error = LW_TRUE; |
409 | 0 | lwerror("Pointarray length (%d) is too large", npoints); |
410 | 0 | return NULL; |
411 | 0 | } |
412 | | |
413 | 0 | LWDEBUGF(4,"Pointarray has %d points", npoints); |
414 | | |
415 | | /* Empty! */ |
416 | 0 | if( npoints == 0 ) |
417 | 0 | return ptarray_construct(s->has_z, s->has_m, npoints); |
418 | | |
419 | | /* Does the data we want to read exist? */ |
420 | 0 | pa_size = (size_t)npoints * ndims * WKB_DOUBLE_SIZE; |
421 | 0 | wkb_parse_state_check(s, pa_size); |
422 | 0 | if (s->error) |
423 | 0 | return NULL; |
424 | | |
425 | | /* If we're in a native endianness, we can just copy the data directly! */ |
426 | 0 | if( ! s->swap_bytes ) |
427 | 0 | { |
428 | 0 | pa = ptarray_construct_copy_data(s->has_z, s->has_m, npoints, (uint8_t*)s->pos); |
429 | 0 | s->pos += pa_size; |
430 | 0 | } |
431 | | /* Otherwise we have to read each double, separately. */ |
432 | 0 | else |
433 | 0 | { |
434 | 0 | uint32_t i = 0; |
435 | 0 | double *dlist; |
436 | 0 | pa = ptarray_construct(s->has_z, s->has_m, npoints); |
437 | 0 | dlist = (double*)(pa->serialized_pointlist); |
438 | 0 | for( i = 0; i < npoints * ndims; i++ ) |
439 | 0 | { |
440 | 0 | dlist[i] = double_from_wkb_state(s); |
441 | 0 | } |
442 | 0 | } |
443 | |
|
444 | 0 | return pa; |
445 | 0 | } |
446 | | |
447 | | /** |
448 | | * POINT |
449 | | * Read a WKB point, starting just after the endian byte, |
450 | | * type number and optional srid number. |
451 | | * Advance the parse state forward appropriately. |
452 | | * WKB point has just a set of doubles, with the quantity depending on the |
453 | | * dimension of the point, so this looks like a special case of the above |
454 | | * with only one point. |
455 | | */ |
456 | | static LWPOINT* lwpoint_from_wkb_state(wkb_parse_state *s) |
457 | 0 | { |
458 | 0 | static uint32_t npoints = 1; |
459 | 0 | POINTARRAY *pa = NULL; |
460 | 0 | size_t pa_size; |
461 | 0 | uint32_t ndims = 2; |
462 | 0 | const POINT2D *pt; |
463 | | |
464 | | /* Count the dimensions. */ |
465 | 0 | if( s->has_z ) ndims++; |
466 | 0 | if( s->has_m ) ndims++; |
467 | 0 | pa_size = ndims * WKB_DOUBLE_SIZE; |
468 | | |
469 | | /* Does the data we want to read exist? */ |
470 | 0 | wkb_parse_state_check(s, pa_size); |
471 | 0 | if (s->error) |
472 | 0 | return NULL; |
473 | | |
474 | | /* If we're in a native endianness, we can just copy the data directly! */ |
475 | 0 | if( ! s->swap_bytes ) |
476 | 0 | { |
477 | 0 | pa = ptarray_construct_copy_data(s->has_z, s->has_m, npoints, (uint8_t*)s->pos); |
478 | 0 | s->pos += pa_size; |
479 | 0 | } |
480 | | /* Otherwise we have to read each double, separately */ |
481 | 0 | else |
482 | 0 | { |
483 | 0 | uint32_t i = 0; |
484 | 0 | double *dlist; |
485 | 0 | pa = ptarray_construct(s->has_z, s->has_m, npoints); |
486 | 0 | dlist = (double*)(pa->serialized_pointlist); |
487 | 0 | for( i = 0; i < ndims; i++ ) |
488 | 0 | { |
489 | 0 | dlist[i] = double_from_wkb_state(s); |
490 | 0 | } |
491 | 0 | } |
492 | | |
493 | | /* Check for POINT(NaN NaN) ==> POINT EMPTY */ |
494 | 0 | pt = getPoint2d_cp(pa, 0); |
495 | 0 | if ( isnan(pt->x) && isnan(pt->y) ) |
496 | 0 | { |
497 | 0 | ptarray_free(pa); |
498 | 0 | return lwpoint_construct_empty(s->srid, s->has_z, s->has_m); |
499 | 0 | } |
500 | 0 | else |
501 | 0 | { |
502 | 0 | return lwpoint_construct(s->srid, NULL, pa); |
503 | 0 | } |
504 | 0 | } |
505 | | |
506 | | /** |
507 | | * LINESTRING |
508 | | * Read a WKB linestring, starting just after the endian byte, |
509 | | * type number and optional srid number. Advance the parse state |
510 | | * forward appropriately. |
511 | | * There is only one pointarray in a linestring. Optionally |
512 | | * check for minimal following of rules (two point minimum). |
513 | | */ |
514 | | static LWLINE* lwline_from_wkb_state(wkb_parse_state *s) |
515 | 0 | { |
516 | 0 | POINTARRAY *pa = ptarray_from_wkb_state(s); |
517 | 0 | if (s->error) |
518 | 0 | return NULL; |
519 | | |
520 | 0 | if( pa == NULL || pa->npoints == 0 ) |
521 | 0 | { |
522 | 0 | if (pa) |
523 | 0 | ptarray_free(pa); |
524 | 0 | return lwline_construct_empty(s->srid, s->has_z, s->has_m); |
525 | 0 | } |
526 | | |
527 | 0 | if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 2 ) |
528 | 0 | { |
529 | 0 | lwerror("%s must have at least two points", lwtype_name(s->lwtype)); |
530 | 0 | return NULL; |
531 | 0 | } |
532 | | |
533 | 0 | return lwline_construct(s->srid, NULL, pa); |
534 | 0 | } |
535 | | |
536 | | /** |
537 | | * CIRCULARSTRING |
538 | | * Read a WKB circularstring, starting just after the endian byte, |
539 | | * type number and optional srid number. Advance the parse state |
540 | | * forward appropriately. |
541 | | * There is only one pointarray in a linestring. Optionally |
542 | | * check for minimal following of rules (three point minimum, |
543 | | * odd number of points). |
544 | | */ |
545 | | static LWCIRCSTRING* lwcircstring_from_wkb_state(wkb_parse_state *s) |
546 | 0 | { |
547 | 0 | POINTARRAY *pa = ptarray_from_wkb_state(s); |
548 | 0 | if (s->error) |
549 | 0 | return NULL; |
550 | | |
551 | 0 | if( pa == NULL || pa->npoints == 0 ) |
552 | 0 | { |
553 | 0 | if (pa) |
554 | 0 | ptarray_free(pa); |
555 | 0 | return lwcircstring_construct_empty(s->srid, s->has_z, s->has_m); |
556 | 0 | } |
557 | | |
558 | 0 | if( s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 3 ) |
559 | 0 | { |
560 | 0 | lwerror("%s must have at least three points", lwtype_name(s->lwtype)); |
561 | 0 | return NULL; |
562 | 0 | } |
563 | | |
564 | 0 | if( s->check & LW_PARSER_CHECK_ODD && ! (pa->npoints % 2) ) |
565 | 0 | { |
566 | 0 | lwerror("%s must have an odd number of points", lwtype_name(s->lwtype)); |
567 | 0 | return NULL; |
568 | 0 | } |
569 | | |
570 | 0 | return lwcircstring_construct(s->srid, NULL, pa); |
571 | 0 | } |
572 | | |
573 | | /** |
574 | | * POLYGON |
575 | | * Read a WKB polygon, starting just after the endian byte, |
576 | | * type number and optional srid number. Advance the parse state |
577 | | * forward appropriately. |
578 | | * First read the number of rings, then read each ring |
579 | | * (which are structured as point arrays) |
580 | | */ |
581 | | static LWPOLY* lwpoly_from_wkb_state(wkb_parse_state *s) |
582 | 0 | { |
583 | 0 | uint32_t nrings = integer_from_wkb_state(s); |
584 | 0 | if (s->error) |
585 | 0 | return NULL; |
586 | 0 | uint32_t i = 0; |
587 | 0 | LWPOLY *poly = lwpoly_construct_empty(s->srid, s->has_z, s->has_m); |
588 | |
|
589 | 0 | LWDEBUGF(4,"Polygon has %d rings", nrings); |
590 | | |
591 | | /* Empty polygon? */ |
592 | 0 | if( nrings == 0 ) |
593 | 0 | return poly; |
594 | | |
595 | 0 | for( i = 0; i < nrings; i++ ) |
596 | 0 | { |
597 | 0 | POINTARRAY *pa = ptarray_from_wkb_state(s); |
598 | 0 | if (pa == NULL) |
599 | 0 | { |
600 | 0 | lwpoly_free(poly); |
601 | 0 | return NULL; |
602 | 0 | } |
603 | | |
604 | | /* Check for at least four points. */ |
605 | 0 | if (s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 4) |
606 | 0 | { |
607 | 0 | lwpoly_free(poly); |
608 | 0 | ptarray_free(pa); |
609 | 0 | LWDEBUGF(2, "%s must have at least four points in each ring", lwtype_name(s->lwtype)); |
610 | 0 | lwerror("%s must have at least four points in each ring", lwtype_name(s->lwtype)); |
611 | 0 | return NULL; |
612 | 0 | } |
613 | | |
614 | | /* Check that first and last points are the same. */ |
615 | 0 | if( s->check & LW_PARSER_CHECK_CLOSURE && ! ptarray_is_closed_2d(pa) ) |
616 | 0 | { |
617 | 0 | lwpoly_free(poly); |
618 | 0 | ptarray_free(pa); |
619 | 0 | LWDEBUGF(2, "%s must have closed rings", lwtype_name(s->lwtype)); |
620 | 0 | lwerror("%s must have closed rings", lwtype_name(s->lwtype)); |
621 | 0 | return NULL; |
622 | 0 | } |
623 | | |
624 | | /* Skip zero-member rings, they add nothing */ |
625 | 0 | if ( pa->npoints == 0) |
626 | 0 | { |
627 | 0 | LWDEBUGF(2, "Skipping empty ring [%d]", i); |
628 | 0 | ptarray_free(pa); |
629 | 0 | continue; |
630 | 0 | } |
631 | | |
632 | | /* Add ring to polygon */ |
633 | 0 | if ( lwpoly_add_ring(poly, pa) == LW_FAILURE ) |
634 | 0 | { |
635 | 0 | lwpoly_free(poly); |
636 | 0 | ptarray_free(pa); |
637 | 0 | LWDEBUG(2, "Unable to add ring to polygon"); |
638 | 0 | lwerror("Unable to add ring to polygon"); |
639 | 0 | return NULL; |
640 | 0 | } |
641 | |
|
642 | 0 | } |
643 | 0 | return poly; |
644 | 0 | } |
645 | | |
646 | | /** |
647 | | * TRIANGLE |
648 | | * Read a WKB triangle, starting just after the endian byte, |
649 | | * type number and optional srid number. Advance the parse state |
650 | | * forward appropriately. |
651 | | * Triangles are encoded like polygons in WKB, but more like linestrings |
652 | | * as lwgeometries. |
653 | | */ |
654 | | static LWTRIANGLE* lwtriangle_from_wkb_state(wkb_parse_state *s) |
655 | 0 | { |
656 | 0 | uint32_t nrings = integer_from_wkb_state(s); |
657 | 0 | if (s->error) |
658 | 0 | return NULL; |
659 | | |
660 | | /* Empty triangle? */ |
661 | 0 | if( nrings == 0 ) |
662 | 0 | return lwtriangle_construct_empty(s->srid, s->has_z, s->has_m); |
663 | | |
664 | | /* Should be only one ring. */ |
665 | 0 | if (nrings != 1) |
666 | 0 | { |
667 | 0 | lwerror("Triangle has wrong number of rings: %d", nrings); |
668 | 0 | } |
669 | | |
670 | | /* There's only one ring, we hope? */ |
671 | 0 | POINTARRAY *pa = ptarray_from_wkb_state(s); |
672 | | |
673 | | /* If there's no points, return an empty triangle. */ |
674 | 0 | if (pa == NULL) |
675 | 0 | return lwtriangle_construct_empty(s->srid, s->has_z, s->has_m); |
676 | | |
677 | | /* Check for at least four points. */ |
678 | 0 | if (s->check & LW_PARSER_CHECK_MINPOINTS && pa->npoints < 4) |
679 | 0 | { |
680 | 0 | ptarray_free(pa); |
681 | 0 | lwerror("%s must have at least four points", lwtype_name(s->lwtype)); |
682 | 0 | return NULL; |
683 | 0 | } |
684 | | |
685 | 0 | if (s->check & LW_PARSER_CHECK_ZCLOSURE && !ptarray_is_closed_z(pa)) |
686 | 0 | { |
687 | 0 | ptarray_free(pa); |
688 | 0 | lwerror("%s must have closed rings", lwtype_name(s->lwtype)); |
689 | 0 | return NULL; |
690 | 0 | } |
691 | | |
692 | | /* Empty TRIANGLE starts w/ empty POINTARRAY, free it first */ |
693 | 0 | return lwtriangle_construct(s->srid, NULL, pa); |
694 | 0 | } |
695 | | |
696 | | /** |
697 | | * CURVEPOLYTYPE |
698 | | */ |
699 | | static LWCURVEPOLY* lwcurvepoly_from_wkb_state(wkb_parse_state *s) |
700 | 0 | { |
701 | 0 | uint32_t ngeoms = integer_from_wkb_state(s); |
702 | 0 | if (s->error) |
703 | 0 | return NULL; |
704 | 0 | LWCURVEPOLY *cp = lwcurvepoly_construct_empty(s->srid, s->has_z, s->has_m); |
705 | 0 | LWGEOM *geom = NULL; |
706 | 0 | uint32_t i; |
707 | | |
708 | | /* Empty collection? */ |
709 | 0 | if ( ngeoms == 0 ) |
710 | 0 | return cp; |
711 | | |
712 | 0 | s->depth++; |
713 | 0 | if (s->depth >= LW_PARSER_MAX_DEPTH) |
714 | 0 | { |
715 | 0 | lwgeom_free((LWGEOM *)cp); |
716 | 0 | lwerror("Geometry has too many chained curves"); |
717 | 0 | return NULL; |
718 | 0 | } |
719 | 0 | for ( i = 0; i < ngeoms; i++ ) |
720 | 0 | { |
721 | 0 | geom = lwgeom_from_wkb_state(s); |
722 | 0 | if ( lwcurvepoly_add_ring(cp, geom) == LW_FAILURE ) |
723 | 0 | { |
724 | 0 | lwgeom_free(geom); |
725 | 0 | lwgeom_free((LWGEOM *)cp); |
726 | 0 | lwerror("Unable to add geometry (%p) to curvepoly (%p)", (void *) geom, (void *) cp); |
727 | 0 | return NULL; |
728 | 0 | } |
729 | 0 | } |
730 | 0 | s->depth--; |
731 | |
|
732 | 0 | return cp; |
733 | 0 | } |
734 | | |
735 | | /** |
736 | | * POLYHEDRALSURFACETYPE |
737 | | */ |
738 | | |
739 | | static LWCOLLECTION* lwcollection_from_wkb_state(wkb_parse_state *s); |
740 | | static LWNURBSCURVE* lwnurbscurve_from_wkb_state(wkb_parse_state *s); |
741 | | |
742 | | /** |
743 | | * Parse a collection (MULTI types, COLLECTION, TINTYPE, COMPOUND, CURVEPOLY, etc.) from WKB state. |
744 | | * |
745 | | * Reads the number of component geometries from the WKB parse state, constructs an |
746 | | * empty LWCOLLECTION of the current s->lwtype/srid/dimension flags, then iteratively |
747 | | * parses and appends each component geometry using lwgeom_from_wkb_state(). |
748 | | * |
749 | | * Behavior and side effects: |
750 | | * - Returns a newly allocated LWCOLLECTION containing the parsed components, or NULL on error. |
751 | | * - For an empty collection (component count == 0) returns the empty collection. |
752 | | * - If s->lwtype == POLYHEDRALSURFACETYPE, enables strict Z-closure checking by setting |
753 | | * the LW_PARSER_CHECK_ZCLOSURE flag in s->check before parsing components. |
754 | | * - Increments s->depth while parsing to enforce recursion limits, if depth exceeds |
755 | | * LW_PARSER_MAX_DEPTH the function frees allocated resources, reports an error, and returns NULL. |
756 | | * - On failure to parse or to add a component, frees any allocated geometry/collection and returns NULL. |
757 | | * |
758 | | * Return: |
759 | | * Pointer to a newly constructed LWCOLLECTION on success, or NULL on failure. |
760 | | */ |
761 | | static LWCOLLECTION* lwcollection_from_wkb_state(wkb_parse_state *s) |
762 | 0 | { |
763 | 0 | uint32_t ngeoms = integer_from_wkb_state(s); |
764 | 0 | if (s->error) |
765 | 0 | return NULL; |
766 | 0 | LWCOLLECTION *col = lwcollection_construct_empty(s->lwtype, s->srid, s->has_z, s->has_m); |
767 | 0 | LWGEOM *geom = NULL; |
768 | 0 | uint32_t i; |
769 | 0 | int8_t prev_check = s->check; |
770 | 0 | uint8_t start_depth = s->depth; |
771 | |
|
772 | 0 | LWDEBUGF(4,"Collection has %d components", ngeoms); |
773 | | |
774 | | /* Empty collection? */ |
775 | 0 | if ( ngeoms == 0 ) |
776 | 0 | { |
777 | 0 | s->check = prev_check; |
778 | 0 | return col; |
779 | 0 | } |
780 | | |
781 | | /* Be strict in polyhedral surface closures */ |
782 | 0 | if ( s->lwtype == POLYHEDRALSURFACETYPE ) |
783 | 0 | s->check |= LW_PARSER_CHECK_ZCLOSURE; |
784 | |
|
785 | 0 | s->depth++; |
786 | 0 | if (s->depth >= LW_PARSER_MAX_DEPTH) |
787 | 0 | { |
788 | 0 | lwcollection_free(col); |
789 | 0 | lwerror("Geometry has too many chained collections"); |
790 | 0 | s->check = prev_check; |
791 | 0 | s->depth = start_depth; |
792 | 0 | return NULL; |
793 | 0 | } |
794 | 0 | for ( i = 0; i < ngeoms; i++ ) |
795 | 0 | { |
796 | 0 | geom = lwgeom_from_wkb_state(s); |
797 | 0 | if (!geom || lwcollection_add_lwgeom(col, geom) == NULL ) |
798 | 0 | { |
799 | 0 | lwgeom_free(geom); |
800 | 0 | lwgeom_free((LWGEOM *)col); |
801 | 0 | lwerror("Unable to add geometry (%p) to collection (%p)", (void *) geom, (void *) col); |
802 | 0 | s->check = prev_check; |
803 | 0 | s->depth = start_depth; |
804 | 0 | return NULL; |
805 | 0 | } |
806 | 0 | } |
807 | 0 | s->depth--; |
808 | 0 | s->check = prev_check; |
809 | |
|
810 | 0 | return col; |
811 | 0 | } |
812 | | |
813 | | /** |
814 | | * Parse an ISO/IEC 13249-3:2016 NURBS curve from the current position of a WKB parse state. |
815 | | * |
816 | | * Reads the NURBSCURVE components in WKB order: degree, number of control points, |
817 | | * per-control-point byte-order marker, coordinates (X, Y, optional Z and M), a 1-byte |
818 | | * weight-present flag and optional weight value, then the knot count and knot values. |
819 | | * If control-point count is zero an empty POINTARRAY is constructed with the current |
820 | | * dimensionality. Knot count must be > 0 per the standard. |
821 | | * |
822 | | * On error (invalid data, unexpected EOF, invalid weight bit, allocation failure, or |
823 | | * missing required knots) the function logs an error, frees any partially-allocated |
824 | | * resources and returns NULL. |
825 | | * |
826 | | * Returns a newly-allocated LWNURBSCURVE on success; the caller owns the returned object. |
827 | | * |
828 | | * @return Pointer to constructed LWNURBSCURVE, or NULL on failure. |
829 | | */ |
830 | | static LWNURBSCURVE* lwnurbscurve_from_wkb_state(wkb_parse_state *s) |
831 | 0 | { |
832 | 0 | uint32_t degree = 0, nknots = 0, npoints = 0, ndims; |
833 | 0 | double *weights = NULL, *knots = NULL; |
834 | 0 | POINTARRAY *points = NULL; |
835 | 0 | int all_weights_one = 1; |
836 | 0 | size_t pa_size; |
837 | 0 | static const uint32_t MAXPOINTS = (uint32_t)(UINT_MAX / (WKB_DOUBLE_SIZE * 4)); |
838 | | |
839 | | /* ISO/IEC 13249-3:2016 compliant parsing */ |
840 | 0 | degree = integer_from_wkb_state(s); |
841 | 0 | if (s->error) return NULL; |
842 | 0 | if (degree < 1 || degree > 10) |
843 | 0 | { |
844 | 0 | lwerror("WKB NURBSCURVE: degree %u outside valid range [1,10]", degree); |
845 | 0 | return NULL; |
846 | 0 | } |
847 | | |
848 | | /* Read control points count */ |
849 | 0 | npoints = integer_from_wkb_state(s); |
850 | 0 | if (s->error) return NULL; |
851 | | |
852 | | /* Defensive upper bound (worst-case 4 doubles/point) */ |
853 | 0 | if (npoints > MAXPOINTS) { |
854 | 0 | lwerror("WKB NURBSCURVE: control point count (%u) too large", npoints); |
855 | 0 | return NULL; |
856 | 0 | } |
857 | | |
858 | 0 | if (npoints > 0 && npoints <= degree) { |
859 | 0 | lwerror("WKB NURBSCURVE: degree %u requires at least %llu control points, got %u", |
860 | 0 | degree, (unsigned long long)degree + 1, npoints); |
861 | 0 | return NULL; |
862 | 0 | } |
863 | 0 | const size_t min_point_size = 2 + (2 + (s->has_z ? 1 : 0) + (s->has_m ? 1 : 0)) * WKB_DOUBLE_SIZE; |
864 | 0 | wkb_parse_state_check(s, (size_t)npoints * min_point_size); |
865 | 0 | if (s->error) |
866 | 0 | return NULL; |
867 | | |
868 | | /* Does the data we want to read exist? */ |
869 | 0 | ndims = 2 + s->has_z + s->has_m; |
870 | 0 | pa_size = (size_t)npoints * ndims * WKB_DOUBLE_SIZE; /* coord */ |
871 | 0 | pa_size += npoints * sizeof(double); /* weight */ |
872 | 0 | pa_size += npoints * sizeof(char) * 2; /* endian_byte + weight_byte */ |
873 | 0 | wkb_parse_state_check(s, pa_size); |
874 | 0 | if (s->error) |
875 | 0 | return NULL; |
876 | | |
877 | | /* Initialize points array */ |
878 | 0 | if (npoints > 0) { |
879 | 0 | int8_t save_swap_butes = s->swap_bytes; |
880 | |
|
881 | 0 | points = ptarray_construct(s->has_z, s->has_m, npoints); |
882 | 0 | weights = lwalloc(sizeof(double) * npoints); |
883 | | |
884 | | /* ISO format: each control point has structure: |
885 | | * <byte order> <wkbweightedpoint> <bit> [<wkbweight>] |
886 | | */ |
887 | |
|
888 | 0 | for (uint32_t i = 0; i < npoints; i++) { |
889 | 0 | POINT4D pt = {0, 0, 0, 0}; |
890 | | |
891 | | /* Read byte order for this point (ISO requirement) */ |
892 | 0 | wkb_swap_bytes(s); |
893 | | |
894 | | /* Read point coordinates */ |
895 | 0 | pt.x = double_from_wkb_state(s); |
896 | 0 | if (s->error) { |
897 | 0 | lwfree(weights); |
898 | 0 | ptarray_free(points); |
899 | 0 | return NULL; |
900 | 0 | } |
901 | | |
902 | 0 | pt.y = double_from_wkb_state(s); |
903 | 0 | if (s->error) { |
904 | 0 | lwfree(weights); |
905 | 0 | ptarray_free(points); |
906 | 0 | return NULL; |
907 | 0 | } |
908 | | |
909 | 0 | if (s->has_z) { |
910 | 0 | pt.z = double_from_wkb_state(s); |
911 | 0 | if (s->error) { |
912 | 0 | lwfree(weights); |
913 | 0 | ptarray_free(points); |
914 | 0 | return NULL; |
915 | 0 | } |
916 | 0 | } |
917 | | |
918 | 0 | if (s->has_m) { |
919 | 0 | pt.m = double_from_wkb_state(s); |
920 | 0 | if (s->error) { |
921 | 0 | lwfree(weights); |
922 | 0 | ptarray_free(points); |
923 | 0 | return NULL; |
924 | 0 | } |
925 | 0 | } |
926 | | |
927 | 0 | ptarray_set_point4d(points, i, &pt); |
928 | | |
929 | | /* Read weight bit flag */ |
930 | 0 | uint8_t has_weight = byte_from_wkb_state(s); |
931 | 0 | if (s->error) { |
932 | 0 | lwfree(weights); |
933 | 0 | ptarray_free(points); |
934 | 0 | return NULL; |
935 | 0 | } |
936 | | |
937 | 0 | if (has_weight == 0) { |
938 | | /* Default weight = 1.0 */ |
939 | 0 | weights[i] = 1.0; |
940 | 0 | } else if (has_weight == 1) { |
941 | | /* Custom weight follows */ |
942 | 0 | weights[i] = double_from_wkb_state(s); |
943 | 0 | if (weights[i] <= 0.0) { |
944 | 0 | lwerror("WKB NURBSCURVE: non-positive weight for point %d", i); |
945 | 0 | lwfree(weights); |
946 | 0 | ptarray_free(points); |
947 | 0 | return NULL; |
948 | 0 | } |
949 | 0 | if (s->error) { |
950 | 0 | lwfree(weights); |
951 | 0 | ptarray_free(points); |
952 | 0 | return NULL; |
953 | 0 | } |
954 | 0 | if (weights[i] != 1.0) all_weights_one = 0; |
955 | 0 | } else { |
956 | 0 | lwerror("WKB NURBSCURVE: invalid weight bit %d for point %d (must be 0 or 1)", has_weight, i); |
957 | 0 | lwfree(weights); |
958 | 0 | ptarray_free(points); |
959 | 0 | return NULL; |
960 | 0 | } |
961 | |
|
962 | 0 | } |
963 | | /* Restore original swap state */ |
964 | 0 | s->swap_bytes = save_swap_butes; |
965 | 0 | } |
966 | | |
967 | | /* Read knots (required by WKB standard) */ |
968 | 0 | nknots = integer_from_wkb_state(s); |
969 | 0 | if (s->error) { |
970 | 0 | lwfree(weights); |
971 | 0 | ptarray_free(points); |
972 | 0 | return NULL; |
973 | 0 | } |
974 | | |
975 | 0 | if (npoints == 0) |
976 | 0 | { |
977 | 0 | if (nknots != 0) |
978 | 0 | { |
979 | 0 | lwerror("WKB NURBSCURVE EMPTY: expected 0 knots, got %u", nknots); |
980 | 0 | return NULL; |
981 | 0 | } |
982 | 0 | return lwnurbscurve_construct_empty(s->srid, s->has_z, s->has_m); |
983 | 0 | } |
984 | | |
985 | 0 | if (nknots == 0) { |
986 | 0 | lwerror("WKB NURBSCURVE: knots required by standard (got 0)"); |
987 | 0 | lwfree(weights); |
988 | 0 | ptarray_free(points); |
989 | 0 | return NULL; |
990 | 0 | } |
991 | | |
992 | | /* Validate knot count against B-spline formula */ |
993 | 0 | uint32_t expected_knots = npoints + degree + 1; |
994 | 0 | if (nknots != expected_knots) { |
995 | 0 | lwerror("WKB NURBSCURVE: expected %d knots for degree %d and %d points, got %d", |
996 | 0 | expected_knots, degree, npoints, nknots); |
997 | 0 | lwfree(weights); |
998 | 0 | ptarray_free(points); |
999 | 0 | return NULL; |
1000 | 0 | } |
1001 | | |
1002 | 0 | knots = lwalloc(sizeof(double) * nknots); |
1003 | 0 | for (uint32_t i = 0; i < nknots; i++) { |
1004 | 0 | knots[i] = double_from_wkb_state(s); |
1005 | 0 | if (s->error) { |
1006 | 0 | lwfree(weights); |
1007 | 0 | lwfree(knots); |
1008 | 0 | ptarray_free(points); |
1009 | 0 | return NULL; |
1010 | 0 | } |
1011 | 0 | } |
1012 | 0 | for (uint32_t i = 1; i < nknots; i++) { |
1013 | 0 | if (knots[i] < knots[i-1]) { |
1014 | 0 | lwerror("WKB NURBSCURVE: knot vector must be non-decreasing"); |
1015 | 0 | lwfree(weights); |
1016 | 0 | lwfree(knots); |
1017 | 0 | ptarray_free(points); |
1018 | 0 | return NULL; |
1019 | 0 | } |
1020 | 0 | } |
1021 | | |
1022 | 0 | uint32_t nweights = all_weights_one ? 0U : npoints; |
1023 | 0 | if (all_weights_one) { lwfree(weights); weights = NULL; } |
1024 | 0 | LWNURBSCURVE *curve = lwnurbscurve_construct(s->srid, NULL, degree, points, weights, knots, nweights, nknots); |
1025 | 0 | if (!curve) { |
1026 | 0 | if (weights) lwfree(weights); |
1027 | 0 | if (knots) lwfree(knots); |
1028 | 0 | if (points) ptarray_free(points); /* constructor did not take ownership on failure */ |
1029 | 0 | return NULL; |
1030 | 0 | } |
1031 | 0 | if (weights) lwfree(weights); |
1032 | 0 | if (knots) lwfree(knots); |
1033 | 0 | return curve; |
1034 | 0 | } |
1035 | | |
1036 | | /** |
1037 | | * Parse a single WKB geometry from the given parse state and return it as an LWGEOM. |
1038 | | * |
1039 | | * Reads the leading endian byte, the WKB type (and optional SRID), updates the parse |
1040 | | * state (including byte-swap flag, detected lwtype and srid), and dispatches to the |
1041 | | * specific geometry reader for the detected type. On success returns a newly |
1042 | | * allocated LWGEOM; on error or unsupported type returns NULL and sets s->error. |
1043 | | * |
1044 | | * Side effects: |
1045 | | * - Advances s->pos as data are consumed. |
1046 | | * - May set s->swap_bytes, s->lwtype, s->srid and s->error. |
1047 | | * |
1048 | | * Return: |
1049 | | * Pointer to the parsed LWGEOM, or NULL on error or unsupported geometry type. |
1050 | | */ |
1051 | | LWGEOM* lwgeom_from_wkb_state(wkb_parse_state *s) |
1052 | 0 | { |
1053 | 0 | uint32_t wkb_type; |
1054 | |
|
1055 | 0 | LWDEBUG(4,"Entered function"); |
1056 | |
|
1057 | 0 | wkb_swap_bytes(s); |
1058 | | |
1059 | | /* Read the type number */ |
1060 | 0 | wkb_type = integer_from_wkb_state(s); |
1061 | 0 | if (s->error) |
1062 | 0 | return NULL; |
1063 | 0 | LWDEBUGF(4,"Got WKB type number: 0x%X", wkb_type); |
1064 | 0 | lwtype_from_wkb_state(s, wkb_type); |
1065 | | |
1066 | | /* Read the SRID, if necessary */ |
1067 | 0 | if( s->has_srid ) |
1068 | 0 | { |
1069 | 0 | s->srid = clamp_srid(integer_from_wkb_state(s)); |
1070 | 0 | if (s->error) |
1071 | 0 | return NULL; |
1072 | | /* TODO: warn on explicit UNKNOWN srid ? */ |
1073 | 0 | LWDEBUGF(4,"Got SRID: %u", s->srid); |
1074 | 0 | } |
1075 | | |
1076 | | /* Do the right thing */ |
1077 | 0 | switch( s->lwtype ) |
1078 | 0 | { |
1079 | 0 | case POINTTYPE: |
1080 | 0 | return (LWGEOM*)lwpoint_from_wkb_state(s); |
1081 | 0 | break; |
1082 | 0 | case LINETYPE: |
1083 | 0 | return (LWGEOM*)lwline_from_wkb_state(s); |
1084 | 0 | break; |
1085 | 0 | case CIRCSTRINGTYPE: |
1086 | 0 | return (LWGEOM*)lwcircstring_from_wkb_state(s); |
1087 | 0 | break; |
1088 | 0 | case POLYGONTYPE: |
1089 | 0 | return (LWGEOM*)lwpoly_from_wkb_state(s); |
1090 | 0 | break; |
1091 | 0 | case TRIANGLETYPE: |
1092 | 0 | return (LWGEOM*)lwtriangle_from_wkb_state(s); |
1093 | 0 | break; |
1094 | 0 | case CURVEPOLYTYPE: |
1095 | 0 | return (LWGEOM*)lwcurvepoly_from_wkb_state(s); |
1096 | 0 | break; |
1097 | 0 | case MULTIPOINTTYPE: |
1098 | 0 | case MULTILINETYPE: |
1099 | 0 | case MULTIPOLYGONTYPE: |
1100 | 0 | case COMPOUNDTYPE: |
1101 | 0 | case MULTICURVETYPE: |
1102 | 0 | case MULTISURFACETYPE: |
1103 | 0 | case POLYHEDRALSURFACETYPE: |
1104 | 0 | case TINTYPE: |
1105 | 0 | case COLLECTIONTYPE: |
1106 | 0 | return (LWGEOM*)lwcollection_from_wkb_state(s); |
1107 | 0 | break; |
1108 | 0 | case NURBSCURVETYPE: |
1109 | 0 | return (LWGEOM*)lwnurbscurve_from_wkb_state(s); |
1110 | 0 | break; |
1111 | | /* Unknown type! */ |
1112 | 0 | default: |
1113 | 0 | lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(s->lwtype)); |
1114 | 0 | } |
1115 | | |
1116 | | /* Return value to keep compiler happy. */ |
1117 | 0 | return NULL; |
1118 | |
|
1119 | 0 | } |
1120 | | |
1121 | | /* TODO add check for SRID consistency */ |
1122 | | |
1123 | | /** |
1124 | | * WKB inputs *must* have a declared size, to prevent malformed WKB from reading |
1125 | | * off the end of the memory segment (this stops a malevolent user from declaring |
1126 | | * a one-ring polygon to have 10 rings, causing the WKB reader to walk off the |
1127 | | * end of the memory). |
1128 | | * |
1129 | | * Check is a bitmask of: LW_PARSER_CHECK_MINPOINTS, LW_PARSER_CHECK_ODD, |
1130 | | * LW_PARSER_CHECK_CLOSURE, LW_PARSER_CHECK_NONE, LW_PARSER_CHECK_ALL |
1131 | | */ |
1132 | | LWGEOM* lwgeom_from_wkb(const uint8_t *wkb, const size_t wkb_size, const char check) |
1133 | 0 | { |
1134 | 0 | wkb_parse_state s; |
1135 | | |
1136 | | /* Initialize the state appropriately */ |
1137 | 0 | s.wkb = wkb; |
1138 | 0 | s.wkb_size = wkb_size; |
1139 | 0 | s.swap_bytes = LW_FALSE; |
1140 | 0 | s.check = check; |
1141 | 0 | s.lwtype = 0; |
1142 | 0 | s.srid = SRID_UNKNOWN; |
1143 | 0 | s.has_z = LW_FALSE; |
1144 | 0 | s.has_m = LW_FALSE; |
1145 | 0 | s.has_srid = LW_FALSE; |
1146 | 0 | s.error = LW_FALSE; |
1147 | 0 | s.pos = wkb; |
1148 | 0 | s.depth = 1; |
1149 | |
|
1150 | 0 | if (!wkb || !wkb_size) |
1151 | 0 | return NULL; |
1152 | | |
1153 | 0 | return lwgeom_from_wkb_state(&s); |
1154 | 0 | } |
1155 | | |
1156 | | LWGEOM* lwgeom_from_hexwkb(const char *hexwkb, const char check) |
1157 | 0 | { |
1158 | 0 | int hexwkb_len; |
1159 | 0 | uint8_t *wkb; |
1160 | 0 | LWGEOM *lwgeom; |
1161 | |
|
1162 | 0 | if ( ! hexwkb ) |
1163 | 0 | { |
1164 | 0 | lwerror("lwgeom_from_hexwkb: null input"); |
1165 | 0 | return NULL; |
1166 | 0 | } |
1167 | | |
1168 | 0 | hexwkb_len = strlen(hexwkb); |
1169 | 0 | wkb = bytes_from_hexbytes(hexwkb, hexwkb_len); |
1170 | 0 | lwgeom = lwgeom_from_wkb(wkb, hexwkb_len/2, check); |
1171 | 0 | lwfree(wkb); |
1172 | 0 | return lwgeom; |
1173 | 0 | } |