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