1 /***********************************************************************
2  *
3  *    GEOS - Geometry Engine Open Source
4  *    http://trac.osgeo.org/geos
5  *
6  *    Copyright (C) 2010 Sandro Santilli <strk@kbt.io>
7  *
8  *    This library is free software; you can redistribute it and/or
9  *    modify it under the terms of the GNU Lesser General Public
10  *    License as published by the Free Software Foundation; either
11  *    version 2.1 of the License, or (at your option) any later version.
12  *
13  *    This library is distributed in the hope that it will be useful,
14  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *    Lesser General Public License for more details.
17  *
18  *    You should have received a copy of the GNU General Public License
19  *    along with this program; if not, write to the Free Software
20  *    Foundation, Inc., 51 Franklin St, Fifth Floor,
21  *    Boston, MA  02110-1301  USA
22  *
23  ***********************************************************************/
24 
25 /* PHP stuff */
26 #include "php.h"
27 #include "ext/standard/info.h" /* for php_info_... */
28 #include "Zend/zend_exceptions.h" /* for zend_throw_exception_object */
29 
30 /* GEOS stuff */
31 #include "geos_c.h"
32 
33 /* Own stuff */
34 #include "php_geos.h"
35 
36 #if PHP_MAJOR_VERSION >= 8
37 #define TSRMLS_C
38 #define TSRMLS_CC
39 #define TSRMLS_DC
40 #define TSRMLS_FETCH()
41 #endif
42 
43 static ZEND_DECLARE_MODULE_GLOBALS(geos);
44 static PHP_GINIT_FUNCTION(geos);
45 
46 PHP_MINIT_FUNCTION(geos);
47 PHP_MSHUTDOWN_FUNCTION(geos);
48 PHP_RINIT_FUNCTION(geos);
49 PHP_RSHUTDOWN_FUNCTION(geos);
50 PHP_MINFO_FUNCTION(geos);
51 PHP_FUNCTION(GEOSVersion);
52 PHP_FUNCTION(GEOSPolygonize);
53 PHP_FUNCTION(GEOSLineMerge);
54 
55 #ifdef HAVE_GEOS_SHARED_PATHS
56 PHP_FUNCTION(GEOSSharedPaths);
57 #endif
58 
59 #ifdef HAVE_GEOS_RELATE_PATTERN_MATCH
60 PHP_FUNCTION(GEOSRelateMatch);
61 #endif
62 
63 #if PHP_VERSION_ID < 50399
64 #define zend_function_entry function_entry
65 #endif
66 
67 #if PHP_VERSION_ID >= 70000
68 # define GEOS_PHP_DTOR_OBJECT zend_object
69 # define zend_object_value zend_object *
70 # define zend_uint size_t
71 # define MAKE_STD_ZVAL(x) x = emalloc(sizeof(zval))
72 # define GEOS_PHP_RETURN_STRING(x) { RETVAL_STRING((x)); efree((x)); return; }
73 # define GEOS_PHP_RETURN_STRINGL(x,s) { RETVAL_STRINGL((x),(s)); efree((x)); return; }
74 # define GEOS_PHP_ADD_ASSOC_ARRAY(a,k,v) { add_assoc_string((a), (k), (v)); efree((v)); }
75 # define GEOS_PHP_ADD_ASSOC_ZVAL(a,k,v) { add_assoc_zval((a), (k), (v)); efree((v)); }
76 # define GEOS_PHP_HASH_GET_CUR_KEY(s,k,i) zend_hash_get_current_key((s), (k), (i))
77 # define GEOS_PHP_HASH_GET_CUR_DATA(h,d) ( d = zend_hash_get_current_data((h)) )
78 # define GEOS_PHP_ZVAL zval *
79 #else /* PHP_VERSION_ID < 70000 */
80 # define GEOS_PHP_DTOR_OBJECT void
81 # define GEOS_PHP_RETURN_STRING(x) RETURN_STRING((x),0)
82 # define GEOS_PHP_RETURN_STRINGL(x,s) RETURN_STRINGL((x),(s),0)
83 # define GEOS_PHP_ADD_ASSOC_ARRAY(a,k,v) add_assoc_string((a), (k), (v), 0)
84 # define GEOS_PHP_ADD_ASSOC_ZVAL(a,k,v) add_assoc_zval((a), (k), (v))
85 # define GEOS_PHP_HASH_GET_CUR_KEY(s,k,i) zend_hash_get_current_key((s), (k), (i), 0)
86 # define zend_string char
87 # define ZSTR_VAL(x) (x)
88 # define GEOS_PHP_HASH_GET_CUR_DATA(h,d) zend_hash_get_current_data((h),(void**)&(d))
89 # define GEOS_PHP_ZVAL zval **
90 #endif
91 
92 
93 static zend_function_entry geos_functions[] = {
94     PHP_FE(GEOSVersion, NULL)
95     PHP_FE(GEOSPolygonize, NULL)
96     PHP_FE(GEOSLineMerge, NULL)
97 
98 #   ifdef HAVE_GEOS_SHARED_PATHS
99     PHP_FE(GEOSSharedPaths, NULL)
100 #   endif
101 
102 #   ifdef HAVE_GEOS_RELATE_PATTERN_MATCH
103     PHP_FE(GEOSRelateMatch, NULL)
104 #   endif
105     {NULL, NULL, NULL}
106 };
107 
108 zend_module_entry geos_module_entry = {
109     STANDARD_MODULE_HEADER,
110     PHP_GEOS_EXTNAME,
111     geos_functions,
112     PHP_MINIT(geos),              /* module init function */
113     PHP_MSHUTDOWN(geos),          /* module shutdown function */
114     PHP_RINIT(geos),              /* request init function */
115     PHP_RSHUTDOWN(geos),          /* request shutdown function */
116     PHP_MINFO(geos),              /* module info function */
117     PHP_GEOS_VERSION,
118     PHP_MODULE_GLOBALS(geos),     /* globals descriptor */
119     PHP_GINIT(geos),              /* globals ctor */
120     NULL,                         /* globals dtor */
121     NULL,                         /* post deactivate */
122     STANDARD_MODULE_PROPERTIES_EX
123 };
124 
125 #ifdef COMPILE_DL_GEOS
ZEND_GET_MODULE(geos)126 ZEND_GET_MODULE(geos)
127 #endif
128 
129 /* -- Utility functions ---------------------- */
130 
131 static void noticeHandler(const char *fmt, ...)
132 {
133     TSRMLS_FETCH();
134     char message[256];
135     va_list args;
136     va_start(args, fmt);
137     vsnprintf(message, sizeof(message) - 1, fmt, args);
138     va_end(args);
139 
140     php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s", message);
141 }
142 
errorHandler(const char * fmt,...)143 static void errorHandler(const char *fmt, ...)
144 {
145     TSRMLS_FETCH();
146     char message[256];
147     va_list args;
148     va_start(args, fmt);
149     vsnprintf(message, sizeof(message) - 1, fmt, args);
150     va_end(args);
151 
152     /* TODO: use a GEOSException ? */
153     zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C),
154         1 TSRMLS_CC, "%s", message);
155 
156 }
157 
158 typedef struct Proxy_t {
159 #if PHP_VERSION_ID >= 70000
160     int id;
161     void* relay;
162     zend_object std;
163 #else
164     zend_object std;
165     void* relay;
166 #endif
167 } Proxy;
168 
169 #if PHP_VERSION_ID >= 70000
php_geos_fetch_object(zend_object * obj)170 static inline Proxy *php_geos_fetch_object(zend_object *obj) {
171   return (Proxy *)((char *) obj - XtOffsetOf(Proxy, std));
172 }
173 # define Z_GEOS_OBJ_P(zv) (Proxy *)((char *) (Z_OBJ_P(zv)) - XtOffsetOf(Proxy, std))
174 #else
175 # ifdef Z_OBJ
176 #  define Z_GEOS_OBJ_P(zv) (Proxy*)Z_OBJ(*val TSRMLS_CC)
177 # else
178 #  define Z_GEOS_OBJ_P(zv) (Proxy*)zend_object_store_get_object(val TSRMLS_CC)
179 # endif
180 #endif
181 
182 static void
setRelay(zval * val,void * obj)183 setRelay(zval* val, void* obj) {
184     TSRMLS_FETCH();
185 
186     Proxy* proxy = Z_GEOS_OBJ_P(val);
187 
188     proxy->relay = obj;
189 }
190 
191 static inline void *
getRelay(zval * val,zend_class_entry * ce)192 getRelay(zval* val, zend_class_entry* ce) {
193     TSRMLS_FETCH();
194 
195     Proxy* proxy = Z_GEOS_OBJ_P(val);
196 
197     if ( proxy->std.ce != ce ) {
198         php_error_docref(NULL TSRMLS_CC, E_ERROR,
199             "Relay object is not an %s", ce->name);
200     }
201     if ( ! proxy->relay ) {
202         php_error_docref(NULL TSRMLS_CC, E_ERROR,
203             "Relay object for object of type %s is not set", ce->name);
204     }
205     return proxy->relay;
206 }
207 
getZvalAsLong(GEOS_PHP_ZVAL val)208 static long getZvalAsLong(GEOS_PHP_ZVAL val)
209 {
210     long ret;
211     zval tmp;
212 
213 #if PHP_VERSION_ID >= 70000
214     tmp = *val;
215 #else
216     tmp = **val;
217 #endif
218     zval_copy_ctor(&tmp);
219     convert_to_long(&tmp);
220     ret = Z_LVAL(tmp);
221     zval_dtor(&tmp);
222     return ret;
223 }
224 
getZvalAsDouble(GEOS_PHP_ZVAL val)225 static long getZvalAsDouble(GEOS_PHP_ZVAL val)
226 {
227     double ret;
228     zval tmp;
229 
230 #if PHP_VERSION_ID >= 70000
231     tmp = *val;
232 #else
233     tmp = **val;
234 #endif
235     zval_copy_ctor(&tmp);
236     convert_to_double(&tmp);
237     ret = Z_DVAL(tmp);
238     zval_dtor(&tmp);
239     return ret;
240 }
241 
242 static zend_object_value
Gen_create_obj(zend_class_entry * type,void (* dtor)(GEOS_PHP_DTOR_OBJECT * object TSRMLS_DC),zend_object_handlers * handlers)243 Gen_create_obj (zend_class_entry *type,
244     void (*dtor)(GEOS_PHP_DTOR_OBJECT *object TSRMLS_DC),
245     zend_object_handlers* handlers)
246 {
247     TSRMLS_FETCH();
248 
249 #if PHP_VERSION_ID >= 70000
250 
251     Proxy *obj = (Proxy *) ecalloc(1, sizeof(Proxy) + zend_object_properties_size(type));
252 
253     zend_object_std_init(&obj->std, type TSRMLS_CC);
254     object_properties_init(&obj->std, type);
255 
256     obj->std.handlers = handlers;
257 
258     /* TODO: install the destructor ? (dtor) ! */
259     /* TODO: do not allocate a full Proxy if we're going to use an object */
260 
261     return &obj->std;
262 
263 #else /* PHP_VERSION_ID < 70000 */
264 
265     zend_object_value retval;
266 
267     Proxy *obj = (Proxy *)ecalloc(1, sizeof(Proxy));
268 
269     obj->std.ce = type;
270 
271     ALLOC_HASHTABLE(obj->std.properties);
272     zend_hash_init(obj->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
273 #if PHP_VERSION_ID < 50399
274     zend_hash_copy(obj->std.properties, &type->default_properties,
275         (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval *));
276 #else
277     object_properties_init(&(obj->std), type);
278 #endif
279 
280     retval.handle = zend_objects_store_put(obj, NULL, dtor, NULL TSRMLS_CC);
281     retval.handlers = handlers;
282 
283     return retval;
284 
285 #endif /* PHP_VERSION_ID < 70000 */
286 }
287 
288 
289 /* -- class GEOSGeometry -------------------- */
290 
291 PHP_METHOD(Geometry, __construct);
292 PHP_METHOD(Geometry, __toString);
293 PHP_METHOD(Geometry, project);
294 PHP_METHOD(Geometry, interpolate);
295 PHP_METHOD(Geometry, buffer);
296 
297 #ifdef HAVE_GEOS_OFFSET_CURVE
298 PHP_METHOD(Geometry, offsetCurve);
299 #endif
300 
301 PHP_METHOD(Geometry, envelope);
302 PHP_METHOD(Geometry, intersection);
303 PHP_METHOD(Geometry, convexHull);
304 PHP_METHOD(Geometry, difference);
305 PHP_METHOD(Geometry, symDifference);
306 PHP_METHOD(Geometry, boundary);
307 PHP_METHOD(Geometry, union); /* also does union cascaded */
308 PHP_METHOD(Geometry, pointOnSurface);
309 PHP_METHOD(Geometry, centroid);
310 PHP_METHOD(Geometry, relate);
311 
312 #ifdef HAVE_GEOS_RELATE_BOUNDARY_NODE_RULE
313 PHP_METHOD(Geometry, relateBoundaryNodeRule);
314 #endif
315 
316 PHP_METHOD(Geometry, simplify); /* also does topology-preserving */
317 PHP_METHOD(Geometry, normalize);
318 
319 #ifdef HAVE_GEOS_GEOM_SET_PRECISION
320 PHP_METHOD(Geometry, setPrecision);
321 #endif
322 
323 #ifdef HAVE_GEOS_GEOM_GET_PRECISION
324 PHP_METHOD(Geometry, getPrecision);
325 #endif
326 
327 #ifdef HAVE_GEOS_GEOM_EXTRACT_UNIQUE_POINTS
328 PHP_METHOD(Geometry, extractUniquePoints);
329 #endif
330 
331 PHP_METHOD(Geometry, disjoint);
332 PHP_METHOD(Geometry, touches);
333 PHP_METHOD(Geometry, intersects);
334 PHP_METHOD(Geometry, crosses);
335 PHP_METHOD(Geometry, within);
336 PHP_METHOD(Geometry, contains);
337 PHP_METHOD(Geometry, overlaps);
338 
339 #ifdef HAVE_GEOS_COVERS
340 PHP_METHOD(Geometry, covers);
341 #endif
342 
343 #ifdef HAVE_GEOS_COVERED_BY
344 PHP_METHOD(Geometry, coveredBy);
345 #endif
346 
347 PHP_METHOD(Geometry, equals);
348 PHP_METHOD(Geometry, equalsExact);
349 PHP_METHOD(Geometry, isEmpty);
350 
351 #ifdef HAVE_GEOS_IS_VALID_DETAIL
352 PHP_METHOD(Geometry, checkValidity);
353 #endif
354 
355 PHP_METHOD(Geometry, isSimple);
356 PHP_METHOD(Geometry, isRing);
357 PHP_METHOD(Geometry, hasZ);
358 
359 #ifdef HAVE_GEOS_IS_CLOSED
360 PHP_METHOD(Geometry, isClosed);
361 #endif
362 
363 PHP_METHOD(Geometry, typeName);
364 PHP_METHOD(Geometry, typeId);
365 PHP_METHOD(Geometry, getSRID);
366 PHP_METHOD(Geometry, setSRID);
367 PHP_METHOD(Geometry, numGeometries);
368 PHP_METHOD(Geometry, geometryN);
369 PHP_METHOD(Geometry, numInteriorRings);
370 
371 #ifdef HAVE_GEOS_GEOM_GET_NUM_POINTS
372 PHP_METHOD(Geometry, numPoints);
373 #endif
374 
375 #ifdef HAVE_GEOS_GEOM_GET_X
376 PHP_METHOD(Geometry, getX);
377 #endif
378 
379 #ifdef HAVE_GEOS_GEOM_GET_Y
380 PHP_METHOD(Geometry, getY);
381 #endif
382 
383 PHP_METHOD(Geometry, interiorRingN);
384 PHP_METHOD(Geometry, exteriorRing);
385 PHP_METHOD(Geometry, numCoordinates);
386 PHP_METHOD(Geometry, dimension);
387 
388 #ifdef HAVE_GEOS_GEOM_GET_COORDINATE_DIMENSION
389 PHP_METHOD(Geometry, coordinateDimension);
390 #endif
391 
392 #ifdef HAVE_GEOS_GEOM_GET_POINT_N
393 PHP_METHOD(Geometry, pointN);
394 #endif
395 
396 #ifdef HAVE_GEOS_GEOM_GET_START_POINT
397 PHP_METHOD(Geometry, startPoint);
398 #endif
399 
400 #ifdef HAVE_GEOS_GEOM_GET_END_POINT
401 PHP_METHOD(Geometry, endPoint);
402 #endif
403 
404 PHP_METHOD(Geometry, area);
405 PHP_METHOD(Geometry, length);
406 PHP_METHOD(Geometry, distance);
407 PHP_METHOD(Geometry, hausdorffDistance);
408 
409 #ifdef HAVE_GEOS_SNAP
410 PHP_METHOD(Geometry, snapTo);
411 #endif
412 
413 #ifdef HAVE_GEOS_NODE
414 PHP_METHOD(Geometry, node);
415 #endif
416 
417 #ifdef HAVE_GEOS_DELAUNAY_TRIANGULATION
418 PHP_METHOD(Geometry, delaunayTriangulation);
419 #endif
420 
421 #ifdef HAVE_GEOS_VORONOI_DIAGRAM
422 PHP_METHOD(Geometry, voronoiDiagram);
423 #endif
424 
425 #ifdef HAVE_GEOS_CLIP_BY_RECT
426 PHP_METHOD(Geometry, clipByRect);
427 #endif
428 
429 static zend_function_entry Geometry_methods[] = {
430     PHP_ME(Geometry, __construct, NULL, 0)
431     PHP_ME(Geometry, __toString, NULL, 0)
432     PHP_ME(Geometry, project, NULL, 0)
433     PHP_ME(Geometry, interpolate, NULL, 0)
434     PHP_ME(Geometry, buffer, NULL, 0)
435 
436 #   ifdef HAVE_GEOS_OFFSET_CURVE
437     PHP_ME(Geometry, offsetCurve, NULL, 0)
438 #   endif
439 
440     PHP_ME(Geometry, envelope, NULL, 0)
441     PHP_ME(Geometry, intersection, NULL, 0)
442     PHP_ME(Geometry, convexHull, NULL, 0)
443     PHP_ME(Geometry, difference, NULL, 0)
444     PHP_ME(Geometry, symDifference, NULL, 0)
445     PHP_ME(Geometry, boundary, NULL, 0)
446     PHP_ME(Geometry, union, NULL, 0)
447     PHP_ME(Geometry, pointOnSurface, NULL, 0)
448     PHP_ME(Geometry, centroid, NULL, 0)
449     PHP_ME(Geometry, relate, NULL, 0)
450 
451 #   ifdef HAVE_GEOS_RELATE_BOUNDARY_NODE_RULE
452     PHP_ME(Geometry, relateBoundaryNodeRule, NULL, 0)
453 #   endif
454 
455     PHP_ME(Geometry, simplify, NULL, 0)
456     PHP_ME(Geometry, normalize, NULL, 0)
457 
458 #   ifdef HAVE_GEOS_GEOM_SET_PRECISION
459     PHP_ME(Geometry, setPrecision, NULL, 0)
460 #   endif
461 
462 #   if HAVE_GEOS_GEOM_GET_PRECISION
463     PHP_ME(Geometry, getPrecision, NULL, 0)
464 #   endif
465 
466 #   ifdef HAVE_GEOS_GEOM_EXTRACT_UNIQUE_POINTS
467     PHP_ME(Geometry, extractUniquePoints, NULL, 0)
468 #   endif
469 
470     PHP_ME(Geometry, disjoint, NULL, 0)
471     PHP_ME(Geometry, touches, NULL, 0)
472     PHP_ME(Geometry, intersects, NULL, 0)
473     PHP_ME(Geometry, crosses, NULL, 0)
474     PHP_ME(Geometry, within, NULL, 0)
475     PHP_ME(Geometry, contains, NULL, 0)
476     PHP_ME(Geometry, overlaps, NULL, 0)
477 
478 #   ifdef HAVE_GEOS_COVERS
479     PHP_ME(Geometry, covers, NULL, 0)
480 #   endif
481 
482 #   ifdef HAVE_GEOS_COVERED_BY
483     PHP_ME(Geometry, coveredBy, NULL, 0)
484 #   endif
485 
486     PHP_ME(Geometry, equals, NULL, 0)
487     PHP_ME(Geometry, equalsExact, NULL, 0)
488     PHP_ME(Geometry, isEmpty, NULL, 0)
489 
490 #   ifdef HAVE_GEOS_IS_VALID_DETAIL
491     PHP_ME(Geometry, checkValidity, NULL, 0)
492 #   endif
493 
494     PHP_ME(Geometry, isSimple, NULL, 0)
495     PHP_ME(Geometry, isRing, NULL, 0)
496     PHP_ME(Geometry, hasZ, NULL, 0)
497 
498 #   ifdef HAVE_GEOS_IS_CLOSED
499     PHP_ME(Geometry, isClosed, NULL, 0)
500 #   endif
501 
502     PHP_ME(Geometry, typeName, NULL, 0)
503     PHP_ME(Geometry, typeId, NULL, 0)
504     PHP_ME(Geometry, getSRID, NULL, 0)
505     PHP_ME(Geometry, setSRID, NULL, 0)
506     PHP_ME(Geometry, numGeometries, NULL, 0)
507     PHP_ME(Geometry, geometryN, NULL, 0)
508     PHP_ME(Geometry, numInteriorRings, NULL, 0)
509 
510 #   ifdef HAVE_GEOS_GEOM_GET_NUM_POINTS
511     PHP_ME(Geometry, numPoints, NULL, 0)
512 #   endif
513 
514 #   ifdef HAVE_GEOS_GEOM_GET_X
515     PHP_ME(Geometry, getX, NULL, 0)
516 #   endif
517 
518 #   ifdef HAVE_GEOS_GEOM_GET_Y
519     PHP_ME(Geometry, getY, NULL, 0)
520 #   endif
521 
522     PHP_ME(Geometry, interiorRingN, NULL, 0)
523     PHP_ME(Geometry, exteriorRing, NULL, 0)
524     PHP_ME(Geometry, numCoordinates, NULL, 0)
525     PHP_ME(Geometry, dimension, NULL, 0)
526 
527 #   ifdef HAVE_GEOS_GEOM_GET_COORDINATE_DIMENSION
528     PHP_ME(Geometry, coordinateDimension, NULL, 0)
529 #   endif
530 
531 #   ifdef HAVE_GEOS_GEOM_GET_POINT_N
532     PHP_ME(Geometry, pointN, NULL, 0)
533 #   endif
534 
535 #   ifdef HAVE_GEOS_GEOM_GET_START_POINT
536     PHP_ME(Geometry, startPoint, NULL, 0)
537 #   endif
538 
539 #   ifdef HAVE_GEOS_GEOM_GET_END_POINT
540     PHP_ME(Geometry, endPoint, NULL, 0)
541 #   endif
542 
543     PHP_ME(Geometry, area, NULL, 0)
544     PHP_ME(Geometry, length, NULL, 0)
545     PHP_ME(Geometry, distance, NULL, 0)
546     PHP_ME(Geometry, hausdorffDistance, NULL, 0)
547 
548 #   if HAVE_GEOS_SNAP
549     PHP_ME(Geometry, snapTo, NULL, 0)
550 #   endif
551 
552 #   ifdef HAVE_GEOS_NODE
553     PHP_ME(Geometry, node, NULL, 0)
554 #   endif
555 
556 #   ifdef HAVE_GEOS_DELAUNAY_TRIANGULATION
557     PHP_ME(Geometry, delaunayTriangulation, NULL, 0)
558 #   endif
559 
560 #   ifdef HAVE_GEOS_VORONOI_DIAGRAM
561     PHP_ME(Geometry, voronoiDiagram, NULL, 0)
562 #   endif
563 
564 #   ifdef HAVE_GEOS_CLIP_BY_RECT
565     PHP_ME(Geometry, clipByRect, NULL, 0)
566 #   endif
567 
568     {NULL, NULL, NULL}
569 };
570 
571 static zend_class_entry *Geometry_ce_ptr;
572 
573 static zend_object_handlers Geometry_object_handlers;
574 
575 /* Geometry serializer */
576 
577 static GEOSWKBWriter* Geometry_serializer = 0;
578 
getGeometrySerializer()579 static GEOSWKBWriter* getGeometrySerializer()
580 {
581     TSRMLS_FETCH();
582 
583     if ( ! Geometry_serializer ) {
584         Geometry_serializer = GEOSWKBWriter_create_r(GEOS_G(handle));
585         GEOSWKBWriter_setIncludeSRID_r(GEOS_G(handle), Geometry_serializer, 1);
586         GEOSWKBWriter_setOutputDimension_r(GEOS_G(handle), Geometry_serializer, 3);
587     }
588     return Geometry_serializer;
589 }
590 
delGeometrySerializer()591 static void delGeometrySerializer()
592 {
593     TSRMLS_FETCH();
594 
595     if ( Geometry_serializer ) {
596         GEOSWKBWriter_destroy_r(GEOS_G(handle), Geometry_serializer);
597     }
598 }
599 
600 /* Geometry deserializer */
601 
602 static GEOSWKBReader* Geometry_deserializer = 0;
603 
getGeometryDeserializer()604 static GEOSWKBReader* getGeometryDeserializer()
605 {
606     TSRMLS_FETCH();
607 
608     if ( ! Geometry_deserializer ) {
609         Geometry_deserializer = GEOSWKBReader_create_r(GEOS_G(handle));
610     }
611     return Geometry_deserializer;
612 }
613 
delGeometryDeserializer()614 static void delGeometryDeserializer()
615 {
616     TSRMLS_FETCH();
617 
618     if ( Geometry_deserializer ) {
619         GEOSWKBReader_destroy_r(GEOS_G(handle), Geometry_deserializer);
620     }
621 }
622 
623 /* Serializer function for GEOSGeometry */
624 
625 static int
Geometry_serialize(zval * object,unsigned char ** buffer,zend_uint * buf_len,zend_serialize_data * data TSRMLS_DC)626 Geometry_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len,
627         zend_serialize_data *data TSRMLS_DC)
628 {
629     GEOSWKBWriter *serializer;
630     GEOSGeometry *geom;
631     char* ret;
632     size_t retsize;
633 
634 
635     serializer = getGeometrySerializer();
636     geom = (GEOSGeometry*)getRelay(object, Geometry_ce_ptr);
637 
638     /* NOTE: we might be fine using binary here */
639     ret = (char*)GEOSWKBWriter_writeHEX_r(GEOS_G(handle), serializer, geom, &retsize);
640     /* we'll probably get an exception if ret is null */
641     if ( ! ret ) return FAILURE;
642 
643     *buffer = (unsigned char*)estrndup(ret, retsize);
644     GEOSFree_r(GEOS_G(handle), ret);
645 
646     *buf_len = retsize;
647 
648     return SUCCESS;
649 }
650 
651 static int
Geometry_deserialize(GEOS_PHP_ZVAL object,zend_class_entry * ce,const unsigned char * buf,zend_uint buf_len,zend_unserialize_data * data TSRMLS_DC)652 Geometry_deserialize(GEOS_PHP_ZVAL object, zend_class_entry *ce, const unsigned char *buf,
653         zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC)
654 {
655     GEOSWKBReader* deserializer;
656     GEOSGeometry* geom;
657 
658     deserializer = getGeometryDeserializer();
659     geom = GEOSWKBReader_readHEX_r(GEOS_G(handle), deserializer, buf, buf_len);
660 
661     /* check zend_class_entry being what we expect! */
662     if ( ce != Geometry_ce_ptr ) {
663         php_error_docref(NULL TSRMLS_CC, E_ERROR,
664                 "Geometry_deserialize called with unexpected zend_class_entry");
665         return FAILURE;
666     }
667 #if PHP_VERSION_ID >= 70000
668     object_init_ex(object, ce);
669     setRelay(object, geom);
670 #else
671     object_init_ex(*object, ce);
672     setRelay(*object, geom);
673 #endif
674 
675     return SUCCESS;
676 }
677 
678 /*
679  * Push components of the given geometry
680  * to the given array zval.
681  * Components geometries are cloned.
682  * NOTE: collection components are not descended into
683  */
684 static void
dumpGeometry(GEOSGeometry * g,zval * array)685 dumpGeometry(GEOSGeometry* g, zval* array)
686 {
687     TSRMLS_FETCH();
688     int ngeoms, i;
689 
690     ngeoms = GEOSGetNumGeometries_r(GEOS_G(handle), g);
691     for (i=0; i<ngeoms; ++i)
692     {
693         zval *tmp;
694         GEOSGeometry* cc;
695         const GEOSGeometry* c = GEOSGetGeometryN_r(GEOS_G(handle), g, i);
696         if ( ! c ) continue; /* should get an exception */
697         /* we _need_ to clone as this one is owned by 'g' */
698         cc = GEOSGeom_clone_r(GEOS_G(handle), c);
699         if ( ! cc ) continue; /* should get an exception */
700 
701         MAKE_STD_ZVAL(tmp);
702         object_init_ex(tmp, Geometry_ce_ptr);
703         setRelay(tmp, cc);
704         add_next_index_zval(array, tmp);
705 #if PHP_VERSION_ID >= 70000
706         efree(tmp);
707 #endif
708     }
709 }
710 
711 
712 static void
Geometry_dtor(GEOS_PHP_DTOR_OBJECT * object TSRMLS_DC)713 Geometry_dtor (GEOS_PHP_DTOR_OBJECT *object TSRMLS_DC)
714 {
715 #if PHP_VERSION_ID < 70000
716     Proxy *obj = (Proxy *)object;
717 #else
718     Proxy *obj = php_geos_fetch_object(object);
719 #endif
720 
721     GEOSGeom_destroy_r(GEOS_G(handle), (GEOSGeometry*)obj->relay);
722 
723 #if PHP_VERSION_ID >= 70000
724     //zend_object_std_dtor(&obj->std);
725 #else
726     zend_hash_destroy(obj->std.properties);
727     FREE_HASHTABLE(obj->std.properties);
728 
729     efree(obj);
730 #endif
731 }
732 
733 static zend_object_value
Geometry_create_obj(zend_class_entry * type TSRMLS_DC)734 Geometry_create_obj (zend_class_entry *type TSRMLS_DC)
735 {
736     return Gen_create_obj(type, Geometry_dtor, &Geometry_object_handlers);
737 }
738 
739 
PHP_METHOD(Geometry,__construct)740 PHP_METHOD(Geometry, __construct)
741 {
742     php_error_docref(NULL TSRMLS_CC, E_ERROR,
743             "GEOSGeometry can't be constructed using new, check WKTReader");
744 
745 }
746 
PHP_METHOD(Geometry,__toString)747 PHP_METHOD(Geometry, __toString)
748 {
749     GEOSGeometry *geom;
750     GEOSWKTWriter *writer;
751     char *wkt;
752     char *ret;
753 
754     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
755     writer = GEOSWKTWriter_create_r(GEOS_G(handle));
756     /* NOTE: if we get an exception before reaching
757      *       GEOSWKTWriter_destory below we'll be leaking memory.
758      *       One fix could be storing the object in a refcounted
759      *       zval.
760      */
761 #   ifdef HAVE_GEOS_WKT_WRITER_SET_TRIM
762     GEOSWKTWriter_setTrim_r(GEOS_G(handle), writer, 1);
763 #   endif
764 
765     wkt = GEOSWKTWriter_write_r(GEOS_G(handle), writer, geom);
766     /* we'll probably get an exception if wkt is null */
767     if ( ! wkt ) RETURN_NULL();
768 
769     GEOSWKTWriter_destroy_r(GEOS_G(handle), writer);
770 
771 
772     ret = estrdup(wkt);
773     GEOSFree_r(GEOS_G(handle), wkt);
774 
775     GEOS_PHP_RETURN_STRING(ret);
776 }
777 
PHP_METHOD(Geometry,project)778 PHP_METHOD(Geometry, project)
779 {
780     GEOSGeometry *this;
781     GEOSGeometry *other;
782     zval *zobj;
783     zend_bool normalized = 0;
784     double ret;
785 
786     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
787 
788     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|b", &zobj,
789             &normalized) == FAILURE) {
790         RETURN_NULL();
791     }
792     other = getRelay(zobj, Geometry_ce_ptr);
793 
794     if ( normalized ) {
795         ret = GEOSProjectNormalized_r(GEOS_G(handle), this, other);
796     } else {
797         ret = GEOSProject_r(GEOS_G(handle), this, other);
798     }
799     if ( ret < 0 ) RETURN_NULL(); /* should get an exception first */
800 
801     RETURN_DOUBLE(ret);
802 }
803 
PHP_METHOD(Geometry,interpolate)804 PHP_METHOD(Geometry, interpolate)
805 {
806     GEOSGeometry *this;
807     double dist;
808     GEOSGeometry *ret;
809     zend_bool normalized = 0;
810 
811     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
812 
813     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|b",
814             &dist, &normalized) == FAILURE) {
815         RETURN_NULL();
816     }
817 
818     if ( normalized ) {
819         ret = GEOSInterpolateNormalized_r(GEOS_G(handle), this, dist);
820     } else {
821         ret = GEOSInterpolate_r(GEOS_G(handle), this, dist);
822     }
823     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
824 
825     /* return_value is a zval */
826     object_init_ex(return_value, Geometry_ce_ptr);
827     setRelay(return_value, ret);
828 }
829 
830 /**
831  * GEOSGeometry::buffer(dist, [<styleArray>])
832  *
833  * styleArray keys supported:
834  *  'quad_segs'
835  *       Type: int
836  *       Number of segments used to approximate
837  *       a quarter circle (defaults to 8).
838  *  'endcap'
839  *       Type: long
840  *       Endcap style (defaults to GEOSBUF_CAP_ROUND)
841  *  'join'
842  *       Type: long
843  *       Join style (defaults to GEOSBUF_JOIN_ROUND)
844  *  'mitre_limit'
845  *       Type: double
846  *       mitre ratio limit (only affects joins with GEOSBUF_JOIN_MITRE style)
847  *       'miter_limit' is also accepted as a synonym for 'mitre_limit'.
848  *  'single_sided'
849  *       Type: bool
850  *       If true buffer lines only on one side, so that the input line
851  *       will be a portion of the boundary of the returned polygon.
852  *       Only applies to lineal input. Defaults to false.
853  */
PHP_METHOD(Geometry,buffer)854 PHP_METHOD(Geometry, buffer)
855 {
856     GEOSGeometry *this;
857     double dist;
858     GEOSGeometry *ret;
859     GEOSBufferParams *params;
860     static const double default_mitreLimit = 5.0;
861     static const int default_endCapStyle = GEOSBUF_CAP_ROUND;
862     static const int default_joinStyle = GEOSBUF_JOIN_ROUND;
863     static const int default_quadSegs = 8;
864     long int quadSegs = default_quadSegs;
865     long int endCapStyle = default_endCapStyle;
866     long int joinStyle = default_joinStyle;
867     double mitreLimit = default_mitreLimit;
868     long singleSided = 0;
869     zval *style_val = NULL;
870     GEOS_PHP_ZVAL data;
871     HashTable *style;
872     zend_string *key;
873     zend_ulong index;
874 
875     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
876 
877     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|a",
878             &dist, &style_val) == FAILURE) {
879         RETURN_NULL();
880     }
881 
882     params = GEOSBufferParams_create_r(GEOS_G(handle));
883 
884     if ( style_val )
885     {
886         style = HASH_OF(style_val);
887         while(GEOS_PHP_HASH_GET_CUR_KEY(style, &key, &index)
888               == HASH_KEY_IS_STRING)
889         {
890             if(!strcmp(ZSTR_VAL(key), "quad_segs"))
891             {
892                 GEOS_PHP_HASH_GET_CUR_DATA(style, data);
893                 quadSegs = getZvalAsLong(data);
894                 GEOSBufferParams_setQuadrantSegments_r(GEOS_G(handle), params, quadSegs);
895             }
896             else if(!strcmp(ZSTR_VAL(key), "endcap"))
897             {
898                 GEOS_PHP_HASH_GET_CUR_DATA(style, data);
899                 endCapStyle = getZvalAsLong(data);
900                 GEOSBufferParams_setEndCapStyle_r(GEOS_G(handle), params, endCapStyle);
901             }
902             else if(!strcmp(ZSTR_VAL(key), "join"))
903             {
904                 GEOS_PHP_HASH_GET_CUR_DATA(style, data);
905                 joinStyle = getZvalAsLong(data);
906                 GEOSBufferParams_setJoinStyle_r(GEOS_G(handle), params, joinStyle);
907             }
908             else if(!strcmp(ZSTR_VAL(key), "mitre_limit"))
909             {
910                 GEOS_PHP_HASH_GET_CUR_DATA(style, data);
911                 mitreLimit = getZvalAsDouble(data);
912                 GEOSBufferParams_setMitreLimit_r(GEOS_G(handle), params, mitreLimit);
913             }
914             else if(!strcmp(ZSTR_VAL(key), "single_sided"))
915             {
916                 GEOS_PHP_HASH_GET_CUR_DATA(style, data);
917                 singleSided = getZvalAsLong(data);
918                 GEOSBufferParams_setSingleSided_r(GEOS_G(handle), params, singleSided);
919             }
920 
921             zend_hash_move_forward(style);
922         }
923     }
924 
925     ret = GEOSBufferWithParams_r(GEOS_G(handle), this, params, dist);
926     GEOSBufferParams_destroy_r(GEOS_G(handle), params);
927     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
928 
929     /* return_value is a zval */
930     object_init_ex(return_value, Geometry_ce_ptr);
931     setRelay(return_value, ret);
932 }
933 
934 /**
935  * GEOSGeometry::offsetCurve(dist, [<styleArray>])
936  *
937  * styleArray keys supported:
938  *  'quad_segs'
939  *       Type: int
940  *       Number of segments used to approximate
941  *       a quarter circle (defaults to 8).
942  *  'join'
943  *       Type: long
944  *       Join style (defaults to GEOSBUF_JOIN_ROUND)
945  *  'mitre_limit'
946  *       Type: double
947  *       mitre ratio limit (only affects joins with GEOSBUF_JOIN_MITRE style)
948  *       'miter_limit' is also accepted as a synonym for 'mitre_limit'.
949  */
950 #ifdef HAVE_GEOS_OFFSET_CURVE
PHP_METHOD(Geometry,offsetCurve)951 PHP_METHOD(Geometry, offsetCurve)
952 {
953     GEOSGeometry *this;
954     double dist;
955     GEOSGeometry *ret;
956     static const double default_mitreLimit = 5.0;
957     static const int default_joinStyle = GEOSBUF_JOIN_ROUND;
958     static const int default_quadSegs = 8;
959     long int quadSegs = default_quadSegs;
960     long int joinStyle = default_joinStyle;
961     double mitreLimit = default_mitreLimit;
962     zval *style_val = NULL;
963     GEOS_PHP_ZVAL data;
964     HashTable *style;
965     zend_string *key;
966     zend_ulong index;
967 
968     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
969 
970     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|a",
971             &dist, &style_val) == FAILURE) {
972         RETURN_NULL();
973     }
974 
975     if ( style_val )
976     {
977         style = HASH_OF(style_val);
978         while(GEOS_PHP_HASH_GET_CUR_KEY(style, &key, &index)
979               == HASH_KEY_IS_STRING)
980         {
981             if(!strcmp(ZSTR_VAL(key), "quad_segs"))
982             {
983                 GEOS_PHP_HASH_GET_CUR_DATA(style, data);
984                 quadSegs = getZvalAsLong(data);
985             }
986             else if(!strcmp(ZSTR_VAL(key), "join"))
987             {
988                 GEOS_PHP_HASH_GET_CUR_DATA(style, data);
989                 joinStyle = getZvalAsLong(data);
990             }
991             else if(!strcmp(ZSTR_VAL(key), "mitre_limit"))
992             {
993                 GEOS_PHP_HASH_GET_CUR_DATA(style, data);
994                 mitreLimit = getZvalAsDouble(data);
995             }
996 
997             zend_hash_move_forward(style);
998         }
999     }
1000 
1001     ret = GEOSOffsetCurve_r(GEOS_G(handle), this, dist, quadSegs, joinStyle, mitreLimit);
1002     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1003 
1004     /* return_value is a zval */
1005     object_init_ex(return_value, Geometry_ce_ptr);
1006     setRelay(return_value, ret);
1007 }
1008 #endif
1009 
PHP_METHOD(Geometry,envelope)1010 PHP_METHOD(Geometry, envelope)
1011 {
1012     GEOSGeometry *this;
1013     GEOSGeometry *ret;
1014 
1015     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1016 
1017     ret = GEOSEnvelope_r(GEOS_G(handle), this);
1018     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1019 
1020     /* return_value is a zval */
1021     object_init_ex(return_value, Geometry_ce_ptr);
1022     setRelay(return_value, ret);
1023 }
1024 
PHP_METHOD(Geometry,intersection)1025 PHP_METHOD(Geometry, intersection)
1026 {
1027     GEOSGeometry *this;
1028     GEOSGeometry *other;
1029     GEOSGeometry *ret;
1030     zval *zobj;
1031 
1032     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1033 
1034     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1035             == FAILURE) {
1036         RETURN_NULL();
1037     }
1038     other = getRelay(zobj, Geometry_ce_ptr);
1039 
1040     ret = GEOSIntersection_r(GEOS_G(handle), this, other);
1041     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1042 
1043     /* return_value is a zval */
1044     object_init_ex(return_value, Geometry_ce_ptr);
1045     setRelay(return_value, ret);
1046 }
1047 
1048 /**
1049  * GEOSGeometry GEOSGeometry::clipByRect(xmin,ymin,xmax,ymax)
1050  */
1051 #ifdef HAVE_GEOS_CLIP_BY_RECT
PHP_METHOD(Geometry,clipByRect)1052 PHP_METHOD(Geometry, clipByRect)
1053 {
1054     GEOSGeometry *this;
1055     GEOSGeometry *ret;
1056     double xmin,ymin,xmax,ymax;
1057 
1058     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1059 
1060     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dddd",
1061             &xmin, &ymin, &xmax, &ymax) == FAILURE) {
1062         RETURN_NULL();
1063     }
1064 
1065     ret = GEOSClipByRect_r(GEOS_G(handle), this, xmin, ymin, xmax, ymax);
1066     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1067 
1068     /* return_value is a zval */
1069     object_init_ex(return_value, Geometry_ce_ptr);
1070     setRelay(return_value, ret);
1071 }
1072 #endif
1073 
PHP_METHOD(Geometry,convexHull)1074 PHP_METHOD(Geometry, convexHull)
1075 {
1076     GEOSGeometry *this;
1077     GEOSGeometry *ret;
1078 
1079     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1080 
1081     ret = GEOSConvexHull_r(GEOS_G(handle), this);
1082     if ( ret == NULL ) RETURN_NULL(); /* should get an exception first */
1083 
1084     /* return_value is a zval */
1085     object_init_ex(return_value, Geometry_ce_ptr);
1086     setRelay(return_value, ret);
1087 }
1088 
PHP_METHOD(Geometry,difference)1089 PHP_METHOD(Geometry, difference)
1090 {
1091     GEOSGeometry *this;
1092     GEOSGeometry *other;
1093     GEOSGeometry *ret;
1094     zval *zobj;
1095 
1096     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1097 
1098     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1099             == FAILURE) {
1100         RETURN_NULL();
1101     }
1102     other = getRelay(zobj, Geometry_ce_ptr);
1103 
1104     ret = GEOSDifference_r(GEOS_G(handle), this, other);
1105     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1106 
1107     /* return_value is a zval */
1108     object_init_ex(return_value, Geometry_ce_ptr);
1109     setRelay(return_value, ret);
1110 }
1111 
PHP_METHOD(Geometry,symDifference)1112 PHP_METHOD(Geometry, symDifference)
1113 {
1114     GEOSGeometry *this;
1115     GEOSGeometry *other;
1116     GEOSGeometry *ret;
1117     zval *zobj;
1118 
1119     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1120 
1121     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1122             == FAILURE) {
1123         RETURN_NULL();
1124     }
1125     other = getRelay(zobj, Geometry_ce_ptr);
1126 
1127     ret = GEOSSymDifference_r(GEOS_G(handle), this, other);
1128     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1129 
1130     /* return_value is a zval */
1131     object_init_ex(return_value, Geometry_ce_ptr);
1132     setRelay(return_value, ret);
1133 }
1134 
PHP_METHOD(Geometry,boundary)1135 PHP_METHOD(Geometry, boundary)
1136 {
1137     GEOSGeometry *this;
1138     GEOSGeometry *ret;
1139 
1140     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1141 
1142     ret = GEOSBoundary_r(GEOS_G(handle), this);
1143     if ( ret == NULL ) RETURN_NULL(); /* should get an exception first */
1144 
1145     /* return_value is a zval */
1146     object_init_ex(return_value, Geometry_ce_ptr);
1147     setRelay(return_value, ret);
1148 }
1149 
1150 /**
1151  * GEOSGeometry::union(otherGeom)
1152  * GEOSGeometry::union()
1153  */
PHP_METHOD(Geometry,union)1154 PHP_METHOD(Geometry, union)
1155 {
1156     GEOSGeometry *this;
1157     GEOSGeometry *other;
1158     GEOSGeometry *ret;
1159     zval *zobj = NULL;
1160 
1161     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1162 
1163     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|o", &zobj)
1164             == FAILURE) {
1165         RETURN_NULL();
1166     }
1167 
1168     if ( zobj ) {
1169         other = getRelay(zobj, Geometry_ce_ptr);
1170         ret = GEOSUnion_r(GEOS_G(handle), this, other);
1171     } else {
1172 #       ifdef HAVE_GEOS_UNARY_UNION
1173         ret = GEOSUnaryUnion_r(GEOS_G(handle), this);
1174 #       else
1175         ret = GEOSUnionCascaded_r(GEOS_G(handle), this);
1176 #       endif
1177     }
1178 
1179     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1180 
1181     /* return_value is a zval */
1182     object_init_ex(return_value, Geometry_ce_ptr);
1183     setRelay(return_value, ret);
1184 }
1185 
1186 /**
1187  * GEOSGeometry::pointOnSurface()
1188  */
PHP_METHOD(Geometry,pointOnSurface)1189 PHP_METHOD(Geometry, pointOnSurface)
1190 {
1191     GEOSGeometry *this;
1192     GEOSGeometry *ret;
1193 
1194     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1195 
1196     ret = GEOSPointOnSurface_r(GEOS_G(handle), this);
1197     if ( ret == NULL ) RETURN_NULL(); /* should get an exception first */
1198 
1199     /* return_value is a zval */
1200     object_init_ex(return_value, Geometry_ce_ptr);
1201     setRelay(return_value, ret);
1202 }
1203 
1204 /**
1205  * GEOSGeometry::centroid()
1206  */
PHP_METHOD(Geometry,centroid)1207 PHP_METHOD(Geometry, centroid)
1208 {
1209     GEOSGeometry *this;
1210     GEOSGeometry *ret;
1211 
1212     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1213 
1214     ret = GEOSGetCentroid_r(GEOS_G(handle), this);
1215     if ( ret == NULL ) RETURN_NULL(); /* should get an exception first */
1216 
1217     /* return_value is a zval */
1218     object_init_ex(return_value, Geometry_ce_ptr);
1219     setRelay(return_value, ret);
1220 }
1221 
1222 /**
1223  * GEOSGeometry::relate(otherGeom)
1224  * GEOSGeometry::relate(otherGeom, pattern)
1225  */
PHP_METHOD(Geometry,relate)1226 PHP_METHOD(Geometry, relate)
1227 {
1228     GEOSGeometry *this;
1229     GEOSGeometry *other;
1230     zval *zobj;
1231     char* pat = NULL;
1232 #if PHP_VERSION_ID >= 70000
1233     size_t patlen;
1234 #else
1235     int patlen;
1236 #endif
1237     int retInt;
1238     zend_bool retBool;
1239     char* retStr;
1240 
1241     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1242 
1243     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|s",
1244         &zobj, &pat, &patlen) == FAILURE)
1245     {
1246         RETURN_NULL();
1247     }
1248 
1249     other = getRelay(zobj, Geometry_ce_ptr);
1250 
1251     if ( ! pat ) {
1252         /* we'll compute it */
1253         pat = GEOSRelate_r(GEOS_G(handle), this, other);
1254         if ( ! pat ) RETURN_NULL(); /* should get an exception first */
1255         retStr = estrdup(pat);
1256         GEOSFree_r(GEOS_G(handle), pat);
1257         GEOS_PHP_RETURN_STRING(retStr);
1258     } else {
1259         retInt = GEOSRelatePattern_r(GEOS_G(handle), this, other, pat);
1260         if ( retInt == 2 ) RETURN_NULL(); /* should get an exception first */
1261         retBool = retInt;
1262         RETURN_BOOL(retBool);
1263     }
1264 
1265 }
1266 
1267 /**
1268  * GEOSGeometry::relateBoundaryNodeRule(otherGeom, rule)
1269  */
1270 #ifdef HAVE_GEOS_RELATE_BOUNDARY_NODE_RULE
PHP_METHOD(Geometry,relateBoundaryNodeRule)1271 PHP_METHOD(Geometry, relateBoundaryNodeRule)
1272 {
1273     GEOSGeometry *this;
1274     GEOSGeometry *other;
1275     zval *zobj;
1276     char* pat;
1277     long int bnr = GEOSRELATE_BNR_OGC;
1278     char* retStr;
1279 
1280     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1281 
1282     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ol",
1283         &zobj, &bnr) == FAILURE)
1284     {
1285         RETURN_NULL();
1286     }
1287 
1288     other = getRelay(zobj, Geometry_ce_ptr);
1289 
1290     /* we'll compute it */
1291     pat = GEOSRelateBoundaryNodeRule_r(GEOS_G(handle), this, other, bnr);
1292     if ( ! pat ) RETURN_NULL(); /* should get an exception first */
1293     retStr = estrdup(pat);
1294     GEOSFree_r(GEOS_G(handle), pat);
1295     GEOS_PHP_RETURN_STRING(retStr);
1296 }
1297 #endif
1298 
1299 /**
1300  * GEOSGeometry GEOSGeometry::simplify(tolerance)
1301  * GEOSGeometry GEOSGeometry::simplify(tolerance, preserveTopology)
1302  */
PHP_METHOD(Geometry,simplify)1303 PHP_METHOD(Geometry, simplify)
1304 {
1305     GEOSGeometry *this;
1306     double tolerance;
1307     zend_bool preserveTopology = 0;
1308     GEOSGeometry *ret;
1309 
1310     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1311 
1312     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|b",
1313             &tolerance, &preserveTopology) == FAILURE) {
1314         RETURN_NULL();
1315     }
1316 
1317     if ( preserveTopology ) {
1318         ret = GEOSTopologyPreserveSimplify_r(GEOS_G(handle), this, tolerance);
1319     } else {
1320         ret = GEOSSimplify_r(GEOS_G(handle), this, tolerance);
1321     }
1322 
1323     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1324 
1325     /* return_value is a zval */
1326     object_init_ex(return_value, Geometry_ce_ptr);
1327     setRelay(return_value, ret);
1328 }
1329 
1330 /**
1331  * GEOSGeometry GEOSGeometry::setPrecision(gridsize, [flags])
1332  */
1333 #ifdef HAVE_GEOS_GEOM_SET_PRECISION
PHP_METHOD(Geometry,setPrecision)1334 PHP_METHOD(Geometry, setPrecision)
1335 {
1336     GEOSGeometry *this;
1337     double gridSize;
1338     long int flags = 0;
1339     GEOSGeometry *ret;
1340 
1341     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1342 
1343     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|l",
1344             &gridSize, &flags) == FAILURE) {
1345         RETURN_NULL();
1346     }
1347 
1348     ret = GEOSGeom_setPrecision_r(GEOS_G(handle), this, gridSize, flags);
1349 
1350     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
1351 
1352     /* return_value is a zval */
1353     object_init_ex(return_value, Geometry_ce_ptr);
1354     setRelay(return_value, ret);
1355 }
1356 #endif
1357 
1358 /**
1359  * double GEOSGeometry::getPrecision()
1360  */
1361 #ifdef HAVE_GEOS_GEOM_GET_PRECISION
PHP_METHOD(Geometry,getPrecision)1362 PHP_METHOD(Geometry, getPrecision)
1363 {
1364     GEOSGeometry *geom;
1365     double prec;
1366 
1367     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1368 
1369     prec = GEOSGeom_getPrecision_r(GEOS_G(handle), geom);
1370     if ( prec < 0 ) RETURN_NULL(); /* should get an exception first */
1371 
1372     RETURN_DOUBLE(prec);
1373 }
1374 #endif
1375 
1376 /**
1377  * GEOSGeometry GEOSGeometry::normalize()
1378  */
PHP_METHOD(Geometry,normalize)1379 PHP_METHOD(Geometry, normalize)
1380 {
1381     GEOSGeometry *this;
1382     GEOSGeometry *ret;
1383 
1384     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1385 
1386     ret = GEOSGeom_clone_r(GEOS_G(handle), this);
1387 
1388     if ( ! ret ) RETURN_NULL();
1389 
1390     GEOSNormalize_r(GEOS_G(handle), ret); /* exception should be gotten automatically */
1391 
1392     /* return_value is a zval */
1393     object_init_ex(return_value, Geometry_ce_ptr);
1394     setRelay(return_value, ret);
1395 }
1396 
1397 /**
1398  * GEOSGeometry GEOSGeometry::extractUniquePoints()
1399  */
1400 #ifdef HAVE_GEOS_GEOM_EXTRACT_UNIQUE_POINTS
PHP_METHOD(Geometry,extractUniquePoints)1401 PHP_METHOD(Geometry, extractUniquePoints)
1402 {
1403     GEOSGeometry *this;
1404     GEOSGeometry *ret;
1405 
1406     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1407 
1408     ret = GEOSGeom_extractUniquePoints_r(GEOS_G(handle), this);
1409     if ( ret == NULL ) RETURN_NULL(); /* should get an exception first */
1410 
1411     /* return_value is a zval */
1412     object_init_ex(return_value, Geometry_ce_ptr);
1413     setRelay(return_value, ret);
1414 }
1415 #endif
1416 
1417 /**
1418  * bool GEOSGeometry::disjoint(GEOSGeometry)
1419  */
PHP_METHOD(Geometry,disjoint)1420 PHP_METHOD(Geometry, disjoint)
1421 {
1422     GEOSGeometry *this;
1423     GEOSGeometry *other;
1424     int ret;
1425     zend_bool retBool;
1426     zval *zobj;
1427 
1428     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1429 
1430     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1431             == FAILURE) {
1432         RETURN_NULL();
1433     }
1434     other = getRelay(zobj, Geometry_ce_ptr);
1435 
1436     ret = GEOSDisjoint_r(GEOS_G(handle), this, other);
1437     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1438 
1439     /* return_value is a zval */
1440     retBool = ret;
1441     RETURN_BOOL(retBool);
1442 }
1443 
1444 /**
1445  * bool GEOSGeometry::touches(GEOSGeometry)
1446  */
PHP_METHOD(Geometry,touches)1447 PHP_METHOD(Geometry, touches)
1448 {
1449     GEOSGeometry *this;
1450     GEOSGeometry *other;
1451     int ret;
1452     zend_bool retBool;
1453     zval *zobj;
1454 
1455     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1456 
1457     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1458             == FAILURE) {
1459         RETURN_NULL();
1460     }
1461     other = getRelay(zobj, Geometry_ce_ptr);
1462 
1463     ret = GEOSTouches_r(GEOS_G(handle), this, other);
1464     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1465 
1466     /* return_value is a zval */
1467     retBool = ret;
1468     RETURN_BOOL(retBool);
1469 }
1470 
1471 /**
1472  * bool GEOSGeometry::intersects(GEOSGeometry)
1473  */
PHP_METHOD(Geometry,intersects)1474 PHP_METHOD(Geometry, intersects)
1475 {
1476     GEOSGeometry *this;
1477     GEOSGeometry *other;
1478     int ret;
1479     zend_bool retBool;
1480     zval *zobj;
1481 
1482     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1483 
1484     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1485             == FAILURE) {
1486         RETURN_NULL();
1487     }
1488     other = getRelay(zobj, Geometry_ce_ptr);
1489 
1490     ret = GEOSIntersects_r(GEOS_G(handle), this, other);
1491     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1492 
1493     /* return_value is a zval */
1494     retBool = ret;
1495     RETURN_BOOL(retBool);
1496 }
1497 
1498 /**
1499  * bool GEOSGeometry::crosses(GEOSGeometry)
1500  */
PHP_METHOD(Geometry,crosses)1501 PHP_METHOD(Geometry, crosses)
1502 {
1503     GEOSGeometry *this;
1504     GEOSGeometry *other;
1505     int ret;
1506     zend_bool retBool;
1507     zval *zobj;
1508 
1509     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1510 
1511     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1512             == FAILURE) {
1513         RETURN_NULL();
1514     }
1515     other = getRelay(zobj, Geometry_ce_ptr);
1516 
1517     ret = GEOSCrosses_r(GEOS_G(handle), this, other);
1518     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1519 
1520     /* return_value is a zval */
1521     retBool = ret;
1522     RETURN_BOOL(retBool);
1523 }
1524 
1525 /**
1526  * bool GEOSGeometry::within(GEOSGeometry)
1527  */
PHP_METHOD(Geometry,within)1528 PHP_METHOD(Geometry, within)
1529 {
1530     GEOSGeometry *this;
1531     GEOSGeometry *other;
1532     int ret;
1533     zend_bool retBool;
1534     zval *zobj;
1535 
1536     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1537 
1538     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1539             == FAILURE) {
1540         RETURN_NULL();
1541     }
1542     other = getRelay(zobj, Geometry_ce_ptr);
1543 
1544     ret = GEOSWithin_r(GEOS_G(handle), this, other);
1545     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1546 
1547     /* return_value is a zval */
1548     retBool = ret;
1549     RETURN_BOOL(retBool);
1550 }
1551 
1552 /**
1553  * bool GEOSGeometry::contains(GEOSGeometry)
1554  */
PHP_METHOD(Geometry,contains)1555 PHP_METHOD(Geometry, contains)
1556 {
1557     GEOSGeometry *this;
1558     GEOSGeometry *other;
1559     int ret;
1560     zend_bool retBool;
1561     zval *zobj;
1562 
1563     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1564 
1565     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1566             == FAILURE) {
1567         RETURN_NULL();
1568     }
1569     other = getRelay(zobj, Geometry_ce_ptr);
1570 
1571     ret = GEOSContains_r(GEOS_G(handle), this, other);
1572     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1573 
1574     /* return_value is a zval */
1575     retBool = ret;
1576     RETURN_BOOL(retBool);
1577 }
1578 
1579 /**
1580  * bool GEOSGeometry::overlaps(GEOSGeometry)
1581  */
PHP_METHOD(Geometry,overlaps)1582 PHP_METHOD(Geometry, overlaps)
1583 {
1584     GEOSGeometry *this;
1585     GEOSGeometry *other;
1586     int ret;
1587     zend_bool retBool;
1588     zval *zobj;
1589 
1590     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1591 
1592     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1593             == FAILURE) {
1594         RETURN_NULL();
1595     }
1596     other = getRelay(zobj, Geometry_ce_ptr);
1597 
1598     ret = GEOSOverlaps_r(GEOS_G(handle), this, other);
1599     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1600 
1601     /* return_value is a zval */
1602     retBool = ret;
1603     RETURN_BOOL(retBool);
1604 }
1605 
1606 /**
1607  * bool GEOSGeometry::covers(GEOSGeometry)
1608  */
1609 #ifdef HAVE_GEOS_COVERS
PHP_METHOD(Geometry,covers)1610 PHP_METHOD(Geometry, covers)
1611 {
1612     GEOSGeometry *this;
1613     GEOSGeometry *other;
1614     int ret;
1615     zend_bool retBool;
1616     zval *zobj;
1617 
1618     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1619 
1620     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1621             == FAILURE) {
1622         RETURN_NULL();
1623     }
1624     other = getRelay(zobj, Geometry_ce_ptr);
1625 
1626     ret = GEOSCovers_r(GEOS_G(handle), this, other);
1627     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1628 
1629     /* return_value is a zval */
1630     retBool = ret;
1631     RETURN_BOOL(retBool);
1632 }
1633 #endif
1634 
1635 /**
1636  * bool GEOSGeometry::coveredBy(GEOSGeometry)
1637  */
1638 #ifdef HAVE_GEOS_COVERED_BY
PHP_METHOD(Geometry,coveredBy)1639 PHP_METHOD(Geometry, coveredBy)
1640 {
1641     GEOSGeometry *this;
1642     GEOSGeometry *other;
1643     int ret;
1644     zend_bool retBool;
1645     zval *zobj;
1646 
1647     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1648 
1649     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
1650             == FAILURE) {
1651         RETURN_NULL();
1652     }
1653     other = getRelay(zobj, Geometry_ce_ptr);
1654 
1655     ret = GEOSCoveredBy_r(GEOS_G(handle), this, other);
1656     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1657 
1658     /* return_value is a zval */
1659     retBool = ret;
1660     RETURN_BOOL(retBool);
1661 }
1662 #endif
1663 
1664 /**
1665  * bool GEOSGeometry::equals(GEOSGeometry)
1666  */
PHP_METHOD(Geometry,equals)1667 PHP_METHOD(Geometry, equals)
1668 {
1669     GEOSGeometry *this;
1670     GEOSGeometry *other;
1671     int ret;
1672     zend_bool retBool;
1673     zval *zobj;
1674 
1675     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1676 
1677     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o",
1678         &zobj) == FAILURE) {
1679         RETURN_NULL();
1680     }
1681     other = getRelay(zobj, Geometry_ce_ptr);
1682 
1683     ret = GEOSEquals_r(GEOS_G(handle), this, other);
1684     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1685 
1686     /* return_value is a zval */
1687     retBool = ret;
1688     RETURN_BOOL(retBool);
1689 }
1690 
1691 /**
1692  * bool GEOSGeometry::equalsExact(GEOSGeometry)
1693  * bool GEOSGeometry::equalsExact(GEOSGeometry, double tolerance)
1694  */
PHP_METHOD(Geometry,equalsExact)1695 PHP_METHOD(Geometry, equalsExact)
1696 {
1697     GEOSGeometry *this;
1698     GEOSGeometry *other;
1699     int ret;
1700     double tolerance = 0;
1701     zend_bool retBool;
1702     zval *zobj;
1703 
1704     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1705 
1706     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|d",
1707         &zobj, &tolerance) == FAILURE) {
1708         RETURN_NULL();
1709     }
1710     other = getRelay(zobj, Geometry_ce_ptr);
1711 
1712     ret = GEOSEqualsExact_r(GEOS_G(handle), this, other, tolerance);
1713     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1714 
1715     /* return_value is a zval */
1716     retBool = ret;
1717     RETURN_BOOL(retBool);
1718 }
1719 
1720 /**
1721  * bool GEOSGeometry::isEmpty()
1722  */
PHP_METHOD(Geometry,isEmpty)1723 PHP_METHOD(Geometry, isEmpty)
1724 {
1725     GEOSGeometry *this;
1726     int ret;
1727     zend_bool retBool;
1728 
1729     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1730 
1731     ret = GEOSisEmpty_r(GEOS_G(handle), this);
1732     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1733 
1734     /* return_value is a zval */
1735     retBool = ret;
1736     RETURN_BOOL(retBool);
1737 }
1738 
1739 /**
1740  * array GEOSGeometry::checkValidity()
1741  */
1742 #ifdef HAVE_GEOS_IS_VALID_DETAIL
PHP_METHOD(Geometry,checkValidity)1743 PHP_METHOD(Geometry, checkValidity)
1744 {
1745     GEOSGeometry *this;
1746     GEOSGeometry *location = NULL;
1747     int ret;
1748     char *reason = NULL;
1749     zend_bool retBool;
1750     char *reasonVal = NULL;
1751     zval *locationVal = NULL;
1752     long int flags = 0;
1753 
1754     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1755 
1756     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l",
1757         &flags) == FAILURE) {
1758         RETURN_NULL();
1759     }
1760 
1761     ret = GEOSisValidDetail_r(GEOS_G(handle), this, flags, &reason, &location);
1762     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1763 
1764     if ( reason ) {
1765         reasonVal = estrdup(reason);
1766         GEOSFree_r(GEOS_G(handle), reason);
1767     }
1768 
1769     if ( location ) {
1770         MAKE_STD_ZVAL(locationVal);
1771         object_init_ex(locationVal, Geometry_ce_ptr);
1772         setRelay(locationVal, location);
1773     }
1774 
1775     retBool = ret;
1776 
1777     /* return value is an array */
1778     array_init(return_value);
1779     add_assoc_bool(return_value, "valid", retBool);
1780     if ( reasonVal ) GEOS_PHP_ADD_ASSOC_ARRAY(return_value, "reason", reasonVal);
1781     if ( locationVal ) GEOS_PHP_ADD_ASSOC_ZVAL(return_value, "location", locationVal);
1782 
1783 }
1784 #endif
1785 
1786 /**
1787  * bool GEOSGeometry::isSimple()
1788  */
PHP_METHOD(Geometry,isSimple)1789 PHP_METHOD(Geometry, isSimple)
1790 {
1791     GEOSGeometry *this;
1792     int ret;
1793     zend_bool retBool;
1794 
1795     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1796 
1797     ret = GEOSisSimple_r(GEOS_G(handle), this);
1798     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1799 
1800     /* return_value is a zval */
1801     retBool = ret;
1802     RETURN_BOOL(retBool);
1803 }
1804 
1805 /**
1806  * bool GEOSGeometry::isRing()
1807  */
PHP_METHOD(Geometry,isRing)1808 PHP_METHOD(Geometry, isRing)
1809 {
1810     GEOSGeometry *this;
1811     int ret;
1812     zend_bool retBool;
1813 
1814     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1815 
1816     ret = GEOSisRing_r(GEOS_G(handle), this);
1817     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1818 
1819     /* return_value is a zval */
1820     retBool = ret;
1821     RETURN_BOOL(retBool);
1822 }
1823 
1824 /**
1825  * bool GEOSGeometry::hasZ()
1826  */
PHP_METHOD(Geometry,hasZ)1827 PHP_METHOD(Geometry, hasZ)
1828 {
1829     GEOSGeometry *this;
1830     int ret;
1831     zend_bool retBool;
1832 
1833     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1834 
1835     ret = GEOSHasZ_r(GEOS_G(handle), this);
1836     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1837 
1838     /* return_value is a zval */
1839     retBool = ret;
1840     RETURN_BOOL(retBool);
1841 }
1842 
1843 /**
1844  * bool GEOSGeometry::isClosed()
1845  */
1846 #ifdef HAVE_GEOS_IS_CLOSED
PHP_METHOD(Geometry,isClosed)1847 PHP_METHOD(Geometry, isClosed)
1848 {
1849     GEOSGeometry *this;
1850     int ret;
1851     zend_bool retBool;
1852 
1853     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1854 
1855     ret = GEOSisClosed_r(GEOS_G(handle), this);
1856     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
1857 
1858     /* return_value is a zval */
1859     retBool = ret;
1860     RETURN_BOOL(retBool);
1861 }
1862 #endif
1863 
1864 /**
1865  * string GEOSGeometry::typeName()
1866  */
PHP_METHOD(Geometry,typeName)1867 PHP_METHOD(Geometry, typeName)
1868 {
1869     GEOSGeometry *this;
1870     char *typ;
1871     char *typVal;
1872 
1873     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1874 
1875     /* TODO: define constant strings instead... */
1876 
1877     typ = GEOSGeomType_r(GEOS_G(handle), this);
1878     if ( ! typ ) RETURN_NULL(); /* should get an exception first */
1879 
1880     typVal = estrdup(typ);
1881     GEOSFree_r(GEOS_G(handle), typ);
1882 
1883     GEOS_PHP_RETURN_STRING(typVal);
1884 }
1885 
1886 /**
1887  * long GEOSGeometry::typeId()
1888  */
PHP_METHOD(Geometry,typeId)1889 PHP_METHOD(Geometry, typeId)
1890 {
1891     GEOSGeometry *this;
1892     long typ;
1893 
1894     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1895 
1896     /* TODO: define constant strings instead... */
1897 
1898     typ = GEOSGeomTypeId_r(GEOS_G(handle), this);
1899     if ( typ == -1 ) RETURN_NULL(); /* should get an exception first */
1900 
1901     RETURN_LONG(typ);
1902 }
1903 
1904 /**
1905  * long GEOSGeometry::getSRID()
1906  */
PHP_METHOD(Geometry,getSRID)1907 PHP_METHOD(Geometry, getSRID)
1908 {
1909     GEOSGeometry *geom;
1910     long int ret;
1911 
1912     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1913 
1914     ret = GEOSGetSRID_r(GEOS_G(handle), geom);
1915 
1916     RETURN_LONG(ret);
1917 }
1918 
1919 /**
1920  * void GEOSGeometry::setSRID(long)
1921  */
PHP_METHOD(Geometry,setSRID)1922 PHP_METHOD(Geometry, setSRID)
1923 {
1924     GEOSGeometry *geom;
1925     long int srid;
1926 
1927     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1928 
1929     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
1930         &srid) == FAILURE) {
1931         RETURN_NULL();
1932     }
1933 
1934     GEOSSetSRID_r(GEOS_G(handle), geom, srid);
1935 }
1936 
1937 /**
1938  * long GEOSGeometry::numGeometries()
1939  */
PHP_METHOD(Geometry,numGeometries)1940 PHP_METHOD(Geometry, numGeometries)
1941 {
1942     GEOSGeometry *geom;
1943     long int ret;
1944 
1945     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1946 
1947     ret = GEOSGetNumGeometries_r(GEOS_G(handle), geom);
1948     if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
1949 
1950     RETURN_LONG(ret);
1951 }
1952 
1953 /**
1954  * GEOSGeometry GEOSGeometry::geometryN()
1955  */
PHP_METHOD(Geometry,geometryN)1956 PHP_METHOD(Geometry, geometryN)
1957 {
1958     GEOSGeometry *geom;
1959     const GEOSGeometry *c;
1960     GEOSGeometry *cc;
1961     long int num;
1962 
1963     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1964 
1965     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
1966         &num) == FAILURE) {
1967         RETURN_NULL();
1968     }
1969 
1970     if ( num >= GEOSGetNumGeometries_r(GEOS_G(handle), geom) ) RETURN_NULL();
1971     c = GEOSGetGeometryN_r(GEOS_G(handle), geom, num);
1972     if ( ! c ) RETURN_NULL(); /* should get an exception first */
1973     cc = GEOSGeom_clone_r(GEOS_G(handle), c);
1974     if ( ! cc ) RETURN_NULL(); /* should get an exception first */
1975 
1976     object_init_ex(return_value, Geometry_ce_ptr);
1977     setRelay(return_value, cc);
1978 }
1979 
1980 /**
1981  * long GEOSGeometry::numInteriorRings()
1982  */
PHP_METHOD(Geometry,numInteriorRings)1983 PHP_METHOD(Geometry, numInteriorRings)
1984 {
1985     GEOSGeometry *geom;
1986     long int ret;
1987 
1988     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
1989 
1990     ret = GEOSGetNumInteriorRings_r(GEOS_G(handle), geom);
1991     if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
1992 
1993     RETURN_LONG(ret);
1994 }
1995 
1996 /**
1997  * long GEOSGeometry::numPoints()
1998  */
1999 #ifdef HAVE_GEOS_GEOM_GET_NUM_POINTS
PHP_METHOD(Geometry,numPoints)2000 PHP_METHOD(Geometry, numPoints)
2001 {
2002     GEOSGeometry *geom;
2003     long int ret;
2004 
2005     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2006 
2007     ret = GEOSGeomGetNumPoints_r(GEOS_G(handle), geom);
2008     if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
2009 
2010     RETURN_LONG(ret);
2011 }
2012 #endif
2013 
2014 /**
2015  * double GEOSGeometry::getX()
2016  */
2017 #ifdef HAVE_GEOS_GEOM_GET_X
PHP_METHOD(Geometry,getX)2018 PHP_METHOD(Geometry, getX)
2019 {
2020     GEOSGeometry *geom;
2021     int ret;
2022     double x;
2023 
2024     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2025 
2026     ret = GEOSGeomGetX_r(GEOS_G(handle), geom, &x);
2027     if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
2028 
2029     RETURN_DOUBLE(x);
2030 }
2031 #endif
2032 
2033 /**
2034  * double GEOSGeometry::getY()
2035  */
2036 #ifdef HAVE_GEOS_GEOM_GET_Y
PHP_METHOD(Geometry,getY)2037 PHP_METHOD(Geometry, getY)
2038 {
2039     GEOSGeometry *geom;
2040     int ret;
2041     double y;
2042 
2043     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2044 
2045     ret = GEOSGeomGetY_r(GEOS_G(handle), geom, &y);
2046     if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
2047 
2048     RETURN_DOUBLE(y);
2049 }
2050 #endif
2051 
2052 /**
2053  * GEOSGeometry GEOSGeometry::interiorRingN()
2054  */
PHP_METHOD(Geometry,interiorRingN)2055 PHP_METHOD(Geometry, interiorRingN)
2056 {
2057     GEOSGeometry *geom;
2058     const GEOSGeometry *c;
2059     GEOSGeometry *cc;
2060     long int num;
2061 
2062     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2063 
2064     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
2065         &num) == FAILURE) {
2066         RETURN_NULL();
2067     }
2068 
2069     if ( num >= GEOSGetNumInteriorRings_r(GEOS_G(handle), geom) ) RETURN_NULL();
2070     c = GEOSGetInteriorRingN_r(GEOS_G(handle), geom, num);
2071     if ( ! c ) RETURN_NULL(); /* should get an exception first */
2072     cc = GEOSGeom_clone_r(GEOS_G(handle), c);
2073     if ( ! cc ) RETURN_NULL(); /* should get an exception first */
2074 
2075     object_init_ex(return_value, Geometry_ce_ptr);
2076     setRelay(return_value, cc);
2077 }
2078 
2079 /**
2080  * GEOSGeometry GEOSGeometry::exteriorRing()
2081  */
PHP_METHOD(Geometry,exteriorRing)2082 PHP_METHOD(Geometry, exteriorRing)
2083 {
2084     GEOSGeometry *geom;
2085     const GEOSGeometry *c;
2086     GEOSGeometry *cc;
2087 
2088     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2089 
2090     c = GEOSGetExteriorRing_r(GEOS_G(handle), geom);
2091     if ( ! c ) RETURN_NULL(); /* should get an exception first */
2092     cc = GEOSGeom_clone_r(GEOS_G(handle), c);
2093     if ( ! cc ) RETURN_NULL(); /* should get an exception first */
2094 
2095     object_init_ex(return_value, Geometry_ce_ptr);
2096     setRelay(return_value, cc);
2097 }
2098 
2099 /**
2100  * long GEOSGeometry::numCoordinates()
2101  */
PHP_METHOD(Geometry,numCoordinates)2102 PHP_METHOD(Geometry, numCoordinates)
2103 {
2104     GEOSGeometry *geom;
2105     long int ret;
2106 
2107     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2108 
2109     ret = GEOSGetNumCoordinates_r(GEOS_G(handle), geom);
2110     if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
2111 
2112     RETURN_LONG(ret);
2113 }
2114 
2115 /**
2116  * long GEOSGeometry::dimension()
2117  * 0:puntual 1:lineal 2:areal
2118  */
PHP_METHOD(Geometry,dimension)2119 PHP_METHOD(Geometry, dimension)
2120 {
2121     GEOSGeometry *geom;
2122     long int ret;
2123 
2124     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2125 
2126     ret = GEOSGeom_getDimensions_r(GEOS_G(handle), geom);
2127     if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
2128 
2129     RETURN_LONG(ret);
2130 }
2131 
2132 /**
2133  * long GEOSGeometry::coordinateDimension()
2134  */
2135 #ifdef HAVE_GEOS_GEOM_GET_COORDINATE_DIMENSION
PHP_METHOD(Geometry,coordinateDimension)2136 PHP_METHOD(Geometry, coordinateDimension)
2137 {
2138     GEOSGeometry *geom;
2139     long int ret;
2140 
2141     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2142 
2143     ret = GEOSGeom_getCoordinateDimension_r(GEOS_G(handle), geom);
2144     if ( ret == -1 ) RETURN_NULL(); /* should get an exception first */
2145 
2146     RETURN_LONG(ret);
2147 }
2148 #endif
2149 
2150 /**
2151  * GEOSGeometry GEOSGeometry::pointN()
2152  */
2153 #ifdef HAVE_GEOS_GEOM_GET_POINT_N
PHP_METHOD(Geometry,pointN)2154 PHP_METHOD(Geometry, pointN)
2155 {
2156     GEOSGeometry *geom;
2157     GEOSGeometry *c;
2158     long int num;
2159 
2160     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2161 
2162     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
2163         &num) == FAILURE) {
2164         RETURN_NULL();
2165     }
2166 
2167     if ( num >= GEOSGeomGetNumPoints_r(GEOS_G(handle), geom) ) RETURN_NULL();
2168     c = GEOSGeomGetPointN_r(GEOS_G(handle), geom, num);
2169     if ( ! c ) RETURN_NULL(); /* should get an exception first */
2170 
2171     object_init_ex(return_value, Geometry_ce_ptr);
2172     setRelay(return_value, c);
2173 }
2174 #endif
2175 
2176 /**
2177  * GEOSGeometry GEOSGeometry::startPoint()
2178  */
PHP_METHOD(Geometry,startPoint)2179 PHP_METHOD(Geometry, startPoint)
2180 {
2181     GEOSGeometry *geom;
2182     GEOSGeometry *c;
2183 
2184     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2185 
2186     c = GEOSGeomGetStartPoint_r(GEOS_G(handle), geom);
2187     if ( ! c ) RETURN_NULL(); /* should get an exception first */
2188 
2189     object_init_ex(return_value, Geometry_ce_ptr);
2190     setRelay(return_value, c);
2191 }
2192 
2193 /**
2194  * GEOSGeometry GEOSGeometry::endPoint()
2195  */
PHP_METHOD(Geometry,endPoint)2196 PHP_METHOD(Geometry, endPoint)
2197 {
2198     GEOSGeometry *geom;
2199     GEOSGeometry *c;
2200 
2201     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2202 
2203     c = GEOSGeomGetEndPoint_r(GEOS_G(handle), geom);
2204     if ( ! c ) RETURN_NULL(); /* should get an exception first */
2205 
2206     object_init_ex(return_value, Geometry_ce_ptr);
2207     setRelay(return_value, c);
2208 }
2209 
2210 /**
2211  * double GEOSGeometry::area()
2212  */
PHP_METHOD(Geometry,area)2213 PHP_METHOD(Geometry, area)
2214 {
2215     GEOSGeometry *geom;
2216     double area;
2217     int ret;
2218 
2219     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2220 
2221     ret = GEOSArea_r(GEOS_G(handle), geom, &area);
2222     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
2223 
2224     RETURN_DOUBLE(area);
2225 }
2226 
2227 /**
2228  * double GEOSGeometry::length()
2229  */
PHP_METHOD(Geometry,length)2230 PHP_METHOD(Geometry, length)
2231 {
2232     GEOSGeometry *geom;
2233     double length;
2234     int ret;
2235 
2236     geom = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2237 
2238     ret = GEOSLength_r(GEOS_G(handle), geom, &length);
2239     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
2240 
2241     RETURN_DOUBLE(length);
2242 }
2243 
2244 /**
2245  * double GEOSGeometry::distance(GEOSGeometry)
2246  */
PHP_METHOD(Geometry,distance)2247 PHP_METHOD(Geometry, distance)
2248 {
2249     GEOSGeometry *this;
2250     GEOSGeometry *other;
2251     zval *zobj;
2252     double dist;
2253     int ret;
2254 
2255     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2256 
2257     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o",
2258         &zobj) == FAILURE)
2259     {
2260         RETURN_NULL();
2261     }
2262 
2263     other = getRelay(zobj, Geometry_ce_ptr);
2264 
2265     ret = GEOSDistance_r(GEOS_G(handle), this, other, &dist);
2266     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
2267 
2268     RETURN_DOUBLE(dist);
2269 }
2270 
2271 /**
2272  * double GEOSGeometry::hausdorffDistance(GEOSGeometry)
2273  */
PHP_METHOD(Geometry,hausdorffDistance)2274 PHP_METHOD(Geometry, hausdorffDistance)
2275 {
2276     GEOSGeometry *this;
2277     GEOSGeometry *other;
2278     zval *zobj;
2279     double dist;
2280     int ret;
2281 
2282     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2283 
2284     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o",
2285         &zobj) == FAILURE)
2286     {
2287         RETURN_NULL();
2288     }
2289 
2290     other = getRelay(zobj, Geometry_ce_ptr);
2291 
2292     ret = GEOSHausdorffDistance_r(GEOS_G(handle), this, other, &dist);
2293     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
2294 
2295     RETURN_DOUBLE(dist);
2296 }
2297 
2298 #ifdef HAVE_GEOS_SNAP
PHP_METHOD(Geometry,snapTo)2299 PHP_METHOD(Geometry, snapTo)
2300 {
2301     GEOSGeometry *this;
2302     GEOSGeometry *other;
2303     GEOSGeometry *ret;
2304     double tolerance;
2305     zval *zobj;
2306 
2307     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2308 
2309     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "od", &zobj,
2310             &tolerance) == FAILURE) {
2311         RETURN_NULL();
2312     }
2313     other = getRelay(zobj, Geometry_ce_ptr);
2314 
2315     ret = GEOSSnap_r(GEOS_G(handle), this, other, tolerance);
2316     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
2317 
2318     /* return_value is a zval */
2319     object_init_ex(return_value, Geometry_ce_ptr);
2320     setRelay(return_value, ret);
2321 }
2322 #endif
2323 
2324 #ifdef HAVE_GEOS_NODE
PHP_METHOD(Geometry,node)2325 PHP_METHOD(Geometry, node)
2326 {
2327     GEOSGeometry *this;
2328     GEOSGeometry *ret;
2329 
2330     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
2331 
2332     ret = GEOSNode_r(GEOS_G(handle), this);
2333     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
2334 
2335     /* return_value is a zval */
2336     object_init_ex(return_value, Geometry_ce_ptr);
2337     setRelay(return_value, ret);
2338 }
2339 #endif
2340 
2341 
2342 
2343 /* -- class GEOSWKTReader -------------------- */
2344 
2345 PHP_METHOD(WKTReader, __construct);
2346 PHP_METHOD(WKTReader, read);
2347 
2348 static zend_function_entry WKTReader_methods[] = {
2349     PHP_ME(WKTReader, __construct, NULL, 0)
2350     PHP_ME(WKTReader, read, NULL, 0)
2351     {NULL, NULL, NULL}
2352 };
2353 
2354 static zend_class_entry *WKTReader_ce_ptr;
2355 
2356 static zend_object_handlers WKTReader_object_handlers;
2357 
2358 static void
WKTReader_dtor(GEOS_PHP_DTOR_OBJECT * object TSRMLS_DC)2359 WKTReader_dtor (GEOS_PHP_DTOR_OBJECT *object TSRMLS_DC)
2360 {
2361 #if PHP_VERSION_ID < 70000
2362     Proxy *obj = (Proxy *)object;
2363 #else
2364     Proxy *obj = php_geos_fetch_object(object);
2365 #endif
2366 
2367     GEOSWKTReader *reader = (GEOSWKTReader*)obj->relay;
2368     if (reader) {
2369         GEOSWKTReader_destroy_r(GEOS_G(handle), reader);
2370     }
2371 
2372 #if PHP_VERSION_ID < 70000
2373     zend_hash_destroy(obj->std.properties);
2374     FREE_HASHTABLE(obj->std.properties);
2375 
2376     efree(obj);
2377 #endif
2378 }
2379 
2380 static zend_object_value
WKTReader_create_obj(zend_class_entry * type TSRMLS_DC)2381 WKTReader_create_obj (zend_class_entry *type TSRMLS_DC)
2382 {
2383     return Gen_create_obj(type, WKTReader_dtor, &WKTReader_object_handlers);
2384 }
2385 
2386 
PHP_METHOD(WKTReader,__construct)2387 PHP_METHOD(WKTReader, __construct)
2388 {
2389     GEOSWKTReader* obj;
2390     zval *object = getThis();
2391 
2392     obj = GEOSWKTReader_create_r(GEOS_G(handle));
2393     if ( ! obj ) {
2394         php_error_docref(NULL TSRMLS_CC, E_ERROR,
2395                 "GEOSWKTReader_create() failed (didn't initGEOS?)");
2396     }
2397 
2398     setRelay(object, obj);
2399 }
2400 
PHP_METHOD(WKTReader,read)2401 PHP_METHOD(WKTReader, read)
2402 {
2403     GEOSWKTReader *reader;
2404     GEOSGeometry *geom;
2405     zend_string *wkt;
2406 #if PHP_VERSION_ID < 70000
2407     int wktlen;
2408 #endif
2409 
2410     reader = (GEOSWKTReader*)getRelay(getThis(), WKTReader_ce_ptr);
2411 
2412     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
2413 #if PHP_VERSION_ID >= 70000
2414             "S", &wkt
2415 #else
2416             "s", &wkt, &wktlen
2417 #endif
2418        ) == FAILURE)
2419     {
2420         RETURN_NULL();
2421     }
2422 
2423     geom = GEOSWKTReader_read_r(GEOS_G(handle), reader, ZSTR_VAL(wkt));
2424     /* we'll probably get an exception if geom is null */
2425     if ( ! geom ) RETURN_NULL();
2426 
2427     /* return_value is a zval */
2428     object_init_ex(return_value, Geometry_ce_ptr);
2429     setRelay(return_value, geom);
2430 
2431 }
2432 
2433 /* -- class GEOSWKTWriter -------------------- */
2434 
2435 PHP_METHOD(WKTWriter, __construct);
2436 PHP_METHOD(WKTWriter, write);
2437 
2438 #ifdef HAVE_GEOS_WKT_WRITER_SET_TRIM
2439 PHP_METHOD(WKTWriter, setTrim);
2440 #endif
2441 
2442 #ifdef HAVE_GEOS_WKT_WRITER_SET_ROUNDING_PRECISION
2443 PHP_METHOD(WKTWriter, setRoundingPrecision);
2444 #endif
2445 
2446 #ifdef HAVE_GEOS_WKT_WRITER_SET_OUTPUT_DIMENSION
2447 PHP_METHOD(WKTWriter, setOutputDimension);
2448 #endif
2449 
2450 #ifdef HAVE_GEOS_WKT_WRITER_GET_OUTPUT_DIMENSION
2451 PHP_METHOD(WKTWriter, getOutputDimension);
2452 #endif
2453 
2454 #ifdef HAVE_GEOS_WKT_WRITER_SET_OLD_3D
2455 PHP_METHOD(WKTWriter, setOld3D);
2456 #endif
2457 
2458 static zend_function_entry WKTWriter_methods[] = {
2459     PHP_ME(WKTWriter, __construct, NULL, 0)
2460     PHP_ME(WKTWriter, write, NULL, 0)
2461 
2462 #   ifdef HAVE_GEOS_WKT_WRITER_SET_TRIM
2463     PHP_ME(WKTWriter, setTrim, NULL, 0)
2464 #   endif
2465 
2466 #   ifdef HAVE_GEOS_WKT_WRITER_SET_ROUNDING_PRECISION
2467     PHP_ME(WKTWriter, setRoundingPrecision, NULL, 0)
2468 #   endif
2469 
2470 #   ifdef HAVE_GEOS_WKT_WRITER_SET_OUTPUT_DIMENSION
2471     PHP_ME(WKTWriter, setOutputDimension, NULL, 0)
2472 #   endif
2473 
2474 #   ifdef HAVE_GEOS_WKT_WRITER_GET_OUTPUT_DIMENSION
2475     PHP_ME(WKTWriter, getOutputDimension, NULL, 0)
2476 #   endif
2477 
2478 #   ifdef HAVE_GEOS_WKT_WRITER_SET_OLD_3D
2479     PHP_ME(WKTWriter, setOld3D, NULL, 0)
2480 #   endif
2481 
2482     {NULL, NULL, NULL}
2483 };
2484 
2485 static zend_class_entry *WKTWriter_ce_ptr;
2486 
2487 static zend_object_handlers WKTWriter_object_handlers;
2488 
2489 static void
WKTWriter_dtor(GEOS_PHP_DTOR_OBJECT * object TSRMLS_DC)2490 WKTWriter_dtor (GEOS_PHP_DTOR_OBJECT *object TSRMLS_DC)
2491 {
2492 #if PHP_VERSION_ID < 70000
2493     Proxy *obj = (Proxy *)object;
2494 #else
2495     Proxy *obj = php_geos_fetch_object(object);
2496 #endif
2497 
2498     GEOSWKTWriter_destroy_r(GEOS_G(handle), (GEOSWKTWriter*)obj->relay);
2499 
2500 #if PHP_VERSION_ID >= 70000
2501     //zend_object_std_dtor(&obj->std);
2502 #else
2503     zend_hash_destroy(obj->std.properties);
2504     FREE_HASHTABLE(obj->std.properties);
2505 
2506     efree(obj);
2507 #endif
2508 }
2509 
2510 static zend_object_value
WKTWriter_create_obj(zend_class_entry * type TSRMLS_DC)2511 WKTWriter_create_obj (zend_class_entry *type TSRMLS_DC)
2512 {
2513     return Gen_create_obj(type, WKTWriter_dtor, &WKTWriter_object_handlers);
2514 }
2515 
PHP_METHOD(WKTWriter,__construct)2516 PHP_METHOD(WKTWriter, __construct)
2517 {
2518     GEOSWKTWriter* obj;
2519     zval *object = getThis();
2520 
2521     obj = GEOSWKTWriter_create_r(GEOS_G(handle));
2522     if ( ! obj ) {
2523         php_error_docref(NULL TSRMLS_CC, E_ERROR,
2524                 "GEOSWKTWriter_create() failed (didn't initGEOS?)");
2525     }
2526 
2527     setRelay(object, obj);
2528 }
2529 
PHP_METHOD(WKTWriter,write)2530 PHP_METHOD(WKTWriter, write)
2531 {
2532     GEOSWKTWriter *writer;
2533     zval *zobj;
2534     GEOSGeometry *geom;
2535     char* wkt;
2536     char* retstr;
2537 
2538     writer = (GEOSWKTWriter*)getRelay(getThis(), WKTWriter_ce_ptr);
2539 
2540     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
2541         == FAILURE)
2542     {
2543         RETURN_NULL();
2544     }
2545 
2546     geom = getRelay(zobj, Geometry_ce_ptr);
2547 
2548     wkt = GEOSWKTWriter_write_r(GEOS_G(handle), writer, geom);
2549     /* we'll probably get an exception if wkt is null */
2550     if ( ! wkt ) RETURN_NULL();
2551 
2552     retstr = estrdup(wkt);
2553     GEOSFree_r(GEOS_G(handle), wkt);
2554 
2555     GEOS_PHP_RETURN_STRING(retstr);
2556 }
2557 
2558 #ifdef HAVE_GEOS_WKT_WRITER_SET_TRIM
PHP_METHOD(WKTWriter,setTrim)2559 PHP_METHOD(WKTWriter, setTrim)
2560 {
2561     GEOSWKTWriter *writer;
2562     zend_bool trimval;
2563     char trim;
2564 
2565     writer = (GEOSWKTWriter*)getRelay(getThis(), WKTWriter_ce_ptr);
2566 
2567     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &trimval)
2568         == FAILURE)
2569     {
2570         RETURN_NULL();
2571     }
2572 
2573     trim = trimval;
2574     GEOSWKTWriter_setTrim_r(GEOS_G(handle), writer, trim);
2575 }
2576 #endif
2577 
2578 #ifdef HAVE_GEOS_WKT_WRITER_SET_ROUNDING_PRECISION
PHP_METHOD(WKTWriter,setRoundingPrecision)2579 PHP_METHOD(WKTWriter, setRoundingPrecision)
2580 {
2581     GEOSWKTWriter *writer;
2582     long int prec;
2583 
2584     writer = (GEOSWKTWriter*)getRelay(getThis(), WKTWriter_ce_ptr);
2585 
2586     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &prec)
2587         == FAILURE)
2588     {
2589         RETURN_NULL();
2590     }
2591 
2592     GEOSWKTWriter_setRoundingPrecision_r(GEOS_G(handle), writer, prec);
2593 }
2594 #endif
2595 
2596 /**
2597  * void GEOSWKTWriter::setOutputDimension()
2598  */
2599 #ifdef HAVE_GEOS_WKT_WRITER_SET_OUTPUT_DIMENSION
PHP_METHOD(WKTWriter,setOutputDimension)2600 PHP_METHOD(WKTWriter, setOutputDimension)
2601 {
2602     GEOSWKTWriter *writer;
2603     long int dim;
2604 
2605     writer = (GEOSWKTWriter*)getRelay(getThis(), WKTWriter_ce_ptr);
2606 
2607     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &dim)
2608         == FAILURE)
2609     {
2610         RETURN_NULL();
2611     }
2612 
2613     GEOSWKTWriter_setOutputDimension_r(GEOS_G(handle), writer, dim);
2614 }
2615 #endif
2616 
2617 /**
2618  * long GEOSWKTWriter::getOutputDimension()
2619  */
2620 #ifdef HAVE_GEOS_WKT_WRITER_GET_OUTPUT_DIMENSION
PHP_METHOD(WKTWriter,getOutputDimension)2621 PHP_METHOD(WKTWriter, getOutputDimension)
2622 {
2623     GEOSWKTWriter *writer;
2624     long int ret;
2625 
2626     writer = (GEOSWKTWriter*)getRelay(getThis(), WKTWriter_ce_ptr);
2627 
2628     ret = GEOSWKTWriter_getOutputDimension_r(GEOS_G(handle), writer);
2629 
2630     RETURN_LONG(ret);
2631 }
2632 #endif
2633 
2634 #ifdef HAVE_GEOS_WKT_WRITER_SET_OLD_3D
PHP_METHOD(WKTWriter,setOld3D)2635 PHP_METHOD(WKTWriter, setOld3D)
2636 {
2637     GEOSWKTWriter *writer;
2638     zend_bool bval;
2639     int val;
2640 
2641     writer = (GEOSWKTWriter*)getRelay(getThis(), WKTWriter_ce_ptr);
2642 
2643     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &bval)
2644         == FAILURE)
2645     {
2646         RETURN_NULL();
2647     }
2648 
2649     val = bval;
2650     GEOSWKTWriter_setOld3D_r(GEOS_G(handle), writer, val);
2651 }
2652 #endif
2653 
2654 /* -- class GEOSWKBWriter -------------------- */
2655 
2656 PHP_METHOD(WKBWriter, __construct);
2657 PHP_METHOD(WKBWriter, getOutputDimension);
2658 PHP_METHOD(WKBWriter, setOutputDimension);
2659 PHP_METHOD(WKBWriter, getByteOrder);
2660 PHP_METHOD(WKBWriter, setByteOrder);
2661 PHP_METHOD(WKBWriter, setIncludeSRID);
2662 PHP_METHOD(WKBWriter, getIncludeSRID);
2663 PHP_METHOD(WKBWriter, write);
2664 PHP_METHOD(WKBWriter, writeHEX);
2665 
2666 static zend_function_entry WKBWriter_methods[] = {
2667     PHP_ME(WKBWriter, __construct, NULL, 0)
2668     PHP_ME(WKBWriter, getOutputDimension, NULL, 0)
2669     PHP_ME(WKBWriter, setOutputDimension, NULL, 0)
2670     PHP_ME(WKBWriter, getByteOrder, NULL, 0)
2671     PHP_ME(WKBWriter, setByteOrder, NULL, 0)
2672     PHP_ME(WKBWriter, getIncludeSRID, NULL, 0)
2673     PHP_ME(WKBWriter, setIncludeSRID, NULL, 0)
2674     PHP_ME(WKBWriter, write, NULL, 0)
2675     PHP_ME(WKBWriter, writeHEX, NULL, 0)
2676     {NULL, NULL, NULL}
2677 };
2678 
2679 static zend_class_entry *WKBWriter_ce_ptr;
2680 
2681 static zend_object_handlers WKBWriter_object_handlers;
2682 
2683 static void
WKBWriter_dtor(GEOS_PHP_DTOR_OBJECT * object TSRMLS_DC)2684 WKBWriter_dtor (GEOS_PHP_DTOR_OBJECT *object TSRMLS_DC)
2685 {
2686 #if PHP_VERSION_ID < 70000
2687     Proxy *obj = (Proxy *)object;
2688 #else
2689     Proxy *obj = php_geos_fetch_object(object);
2690 #endif
2691 
2692     GEOSWKBWriter_destroy_r(GEOS_G(handle), (GEOSWKBWriter*)obj->relay);
2693 
2694 #if PHP_VERSION_ID >= 70000
2695     //zend_object_std_dtor(&obj->std);
2696 #else
2697     zend_hash_destroy(obj->std.properties);
2698     FREE_HASHTABLE(obj->std.properties);
2699 
2700     efree(obj);
2701 #endif
2702 }
2703 
2704 static zend_object_value
WKBWriter_create_obj(zend_class_entry * type TSRMLS_DC)2705 WKBWriter_create_obj (zend_class_entry *type TSRMLS_DC)
2706 {
2707     return Gen_create_obj(type, WKBWriter_dtor, &WKBWriter_object_handlers);
2708 }
2709 
2710 /**
2711  * GEOSWKBWriter w = new GEOSWKBWriter()
2712  */
PHP_METHOD(WKBWriter,__construct)2713 PHP_METHOD(WKBWriter, __construct)
2714 {
2715     GEOSWKBWriter* obj;
2716     zval *object = getThis();
2717 
2718     obj = GEOSWKBWriter_create_r(GEOS_G(handle));
2719     if ( ! obj ) {
2720         php_error_docref(NULL TSRMLS_CC, E_ERROR,
2721                 "GEOSWKBWriter_create() failed (didn't initGEOS?)");
2722     }
2723 
2724     setRelay(object, obj);
2725 }
2726 
2727 /**
2728  * long GEOSWKBWriter::getOutputDimension();
2729  */
PHP_METHOD(WKBWriter,getOutputDimension)2730 PHP_METHOD(WKBWriter, getOutputDimension)
2731 {
2732     GEOSWKBWriter *writer;
2733     long int ret;
2734 
2735     writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2736 
2737     ret = GEOSWKBWriter_getOutputDimension_r(GEOS_G(handle), writer);
2738 
2739     RETURN_LONG(ret);
2740 }
2741 
2742 /**
2743  * void GEOSWKBWriter::setOutputDimension(dims);
2744  */
PHP_METHOD(WKBWriter,setOutputDimension)2745 PHP_METHOD(WKBWriter, setOutputDimension)
2746 {
2747     GEOSWKBWriter *writer;
2748     long int dim;
2749 
2750     writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2751 
2752     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &dim)
2753         == FAILURE)
2754     {
2755         RETURN_NULL();
2756     }
2757 
2758     GEOSWKBWriter_setOutputDimension_r(GEOS_G(handle), writer, dim);
2759 
2760 }
2761 
2762 /**
2763  * string GEOSWKBWriter::write(GEOSGeometry)
2764  */
PHP_METHOD(WKBWriter,write)2765 PHP_METHOD(WKBWriter, write)
2766 {
2767     GEOSWKBWriter *writer;
2768     zval *zobj;
2769     GEOSGeometry *geom;
2770     char *ret;
2771     size_t retsize;
2772     char* retstr;
2773 
2774     writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2775 
2776     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
2777         == FAILURE)
2778     {
2779         RETURN_NULL();
2780     }
2781 
2782     geom = getRelay(zobj, Geometry_ce_ptr);
2783 
2784     ret = (char*)GEOSWKBWriter_write_r(GEOS_G(handle), writer, geom, &retsize);
2785     /* we'll probably get an exception if ret is null */
2786     if ( ! ret ) RETURN_NULL();
2787 
2788     retstr = estrndup(ret, retsize);
2789     GEOSFree_r(GEOS_G(handle), ret);
2790 
2791     GEOS_PHP_RETURN_STRINGL(retstr, retsize);
2792 }
2793 
2794 /**
2795  * string GEOSWKBWriter::writeHEX(GEOSGeometry)
2796  */
PHP_METHOD(WKBWriter,writeHEX)2797 PHP_METHOD(WKBWriter, writeHEX)
2798 {
2799     GEOSWKBWriter *writer;
2800     zval *zobj;
2801     GEOSGeometry *geom;
2802     char *ret;
2803     size_t retsize; /* useless... */
2804     char* retstr;
2805 
2806     writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2807 
2808     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
2809         == FAILURE)
2810     {
2811         RETURN_NULL();
2812     }
2813 
2814     geom = getRelay(zobj, Geometry_ce_ptr);
2815 
2816     ret = (char*)GEOSWKBWriter_writeHEX_r(GEOS_G(handle), writer, geom, &retsize);
2817     /* we'll probably get an exception if ret is null */
2818     if ( ! ret ) RETURN_NULL();
2819 
2820     retstr = estrndup(ret, retsize);
2821     GEOSFree_r(GEOS_G(handle), ret);
2822 
2823     GEOS_PHP_RETURN_STRING(retstr);
2824 }
2825 
2826 /**
2827  * long GEOSWKBWriter::getByteOrder();
2828  */
PHP_METHOD(WKBWriter,getByteOrder)2829 PHP_METHOD(WKBWriter, getByteOrder)
2830 {
2831     GEOSWKBWriter *writer;
2832     long int ret;
2833 
2834     writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2835 
2836     ret = GEOSWKBWriter_getByteOrder_r(GEOS_G(handle), writer);
2837 
2838     RETURN_LONG(ret);
2839 }
2840 
2841 /**
2842  * void GEOSWKBWriter::setByteOrder(dims);
2843  */
PHP_METHOD(WKBWriter,setByteOrder)2844 PHP_METHOD(WKBWriter, setByteOrder)
2845 {
2846     GEOSWKBWriter *writer;
2847     long int dim;
2848 
2849     writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2850 
2851     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &dim)
2852         == FAILURE)
2853     {
2854         RETURN_NULL();
2855     }
2856 
2857     GEOSWKBWriter_setByteOrder_r(GEOS_G(handle), writer, dim);
2858 
2859 }
2860 
2861 /**
2862  * bool GEOSWKBWriter::getIncludeSRID();
2863  */
PHP_METHOD(WKBWriter,getIncludeSRID)2864 PHP_METHOD(WKBWriter, getIncludeSRID)
2865 {
2866     GEOSWKBWriter *writer;
2867     int ret;
2868     zend_bool retBool;
2869 
2870     writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2871 
2872     ret = GEOSWKBWriter_getIncludeSRID_r(GEOS_G(handle), writer);
2873     retBool = ret;
2874 
2875     RETURN_BOOL(retBool);
2876 }
2877 
2878 /**
2879  * void GEOSWKBWriter::setIncludeSRID(bool);
2880  */
PHP_METHOD(WKBWriter,setIncludeSRID)2881 PHP_METHOD(WKBWriter, setIncludeSRID)
2882 {
2883     GEOSWKBWriter *writer;
2884     int inc;
2885     zend_bool incVal;
2886 
2887     writer = (GEOSWKBWriter*)getRelay(getThis(), WKBWriter_ce_ptr);
2888 
2889     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &incVal)
2890         == FAILURE)
2891     {
2892         RETURN_NULL();
2893     }
2894 
2895     inc = incVal;
2896     GEOSWKBWriter_setIncludeSRID_r(GEOS_G(handle), writer, inc);
2897 }
2898 
2899 /* -- class GEOSWKBReader -------------------- */
2900 
2901 PHP_METHOD(WKBReader, __construct);
2902 PHP_METHOD(WKBReader, read);
2903 PHP_METHOD(WKBReader, readHEX);
2904 
2905 static zend_function_entry WKBReader_methods[] = {
2906     PHP_ME(WKBReader, __construct, NULL, 0)
2907     PHP_ME(WKBReader, read, NULL, 0)
2908     PHP_ME(WKBReader, readHEX, NULL, 0)
2909     {NULL, NULL, NULL}
2910 };
2911 
2912 static zend_class_entry *WKBReader_ce_ptr;
2913 
2914 static zend_object_handlers WKBReader_object_handlers;
2915 
2916 static void
WKBReader_dtor(GEOS_PHP_DTOR_OBJECT * object TSRMLS_DC)2917 WKBReader_dtor (GEOS_PHP_DTOR_OBJECT *object TSRMLS_DC)
2918 {
2919 #if PHP_VERSION_ID < 70000
2920     Proxy *obj = (Proxy *)object;
2921 #else
2922     Proxy *obj = php_geos_fetch_object(object);
2923 #endif
2924 
2925     GEOSWKBReader_destroy_r(GEOS_G(handle), (GEOSWKBReader*)obj->relay);
2926 
2927 #if PHP_VERSION_ID >= 70000
2928     //zend_object_std_dtor(&obj->std);
2929 #else
2930     zend_hash_destroy(obj->std.properties);
2931     FREE_HASHTABLE(obj->std.properties);
2932 
2933     efree(obj);
2934 #endif
2935 }
2936 
2937 static zend_object_value
WKBReader_create_obj(zend_class_entry * type TSRMLS_DC)2938 WKBReader_create_obj (zend_class_entry *type TSRMLS_DC)
2939 {
2940     return Gen_create_obj(type, WKBReader_dtor, &WKBReader_object_handlers);
2941 }
2942 
2943 
PHP_METHOD(WKBReader,__construct)2944 PHP_METHOD(WKBReader, __construct)
2945 {
2946     GEOSWKBReader* obj;
2947     zval *object = getThis();
2948 
2949     obj = GEOSWKBReader_create_r(GEOS_G(handle));
2950     if ( ! obj ) {
2951         php_error_docref(NULL TSRMLS_CC, E_ERROR,
2952                 "GEOSWKBReader_create() failed (didn't initGEOS?)");
2953     }
2954 
2955     setRelay(object, obj);
2956 }
2957 
PHP_METHOD(WKBReader,read)2958 PHP_METHOD(WKBReader, read)
2959 {
2960     GEOSWKBReader *reader;
2961     GEOSGeometry *geom;
2962     zend_string* wkb;
2963     int wkblen;
2964 
2965     reader = (GEOSWKBReader*)getRelay(getThis(), WKBReader_ce_ptr);
2966 
2967     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
2968 #if PHP_VERSION_ID >= 70000
2969             "S", &wkb
2970 #else
2971             "s", &wkb, &wkblen
2972 #endif
2973        ) == FAILURE)
2974     {
2975         RETURN_NULL();
2976     }
2977 
2978 #if PHP_VERSION_ID >= 70000
2979     wkblen = ZSTR_LEN(wkb);
2980 #endif
2981 
2982     geom = GEOSWKBReader_read_r(GEOS_G(handle), reader, (unsigned char*)ZSTR_VAL(wkb), wkblen);
2983     /* we'll probably get an exception if geom is null */
2984     if ( ! geom ) RETURN_NULL();
2985 
2986     /* return_value is a zval */
2987     object_init_ex(return_value, Geometry_ce_ptr);
2988     setRelay(return_value, geom);
2989 
2990 }
2991 
PHP_METHOD(WKBReader,readHEX)2992 PHP_METHOD(WKBReader, readHEX)
2993 {
2994     GEOSWKBReader *reader;
2995     GEOSGeometry *geom;
2996     unsigned char* wkb;
2997 #if PHP_VERSION_ID >= 70000
2998     size_t wkblen;
2999 #else
3000     int wkblen;
3001 #endif
3002 
3003     reader = (GEOSWKBReader*)getRelay(getThis(), WKBReader_ce_ptr);
3004 
3005     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
3006         &wkb, &wkblen) == FAILURE)
3007     {
3008         RETURN_NULL();
3009     }
3010 
3011     geom = GEOSWKBReader_readHEX_r(GEOS_G(handle), reader, wkb, wkblen);
3012     /* we'll probably get an exception if geom is null */
3013     if ( ! geom ) RETURN_NULL();
3014 
3015     /* return_value is a zval */
3016     object_init_ex(return_value, Geometry_ce_ptr);
3017     setRelay(return_value, geom);
3018 
3019 }
3020 
3021 
3022 /* -- Free functions ------------------------- */
3023 
3024 /**
3025  * string GEOSVersion()
3026  */
PHP_FUNCTION(GEOSVersion)3027 PHP_FUNCTION(GEOSVersion)
3028 {
3029     char *str;
3030 
3031     str = estrdup(GEOSversion());
3032     GEOS_PHP_RETURN_STRING(str);
3033 }
3034 
3035 /**
3036  * array GEOSPolygonize(GEOSGeometry $geom)
3037  *
3038  * The returned array contains the following elements:
3039  *
3040  *  - 'rings'
3041  *      Type: array of GEOSGeometry
3042  *      Rings that can be formed by the costituent
3043  *      linework of geometry.
3044  *  - 'cut_edges' (optional)
3045  *      Type: array of GEOSGeometry
3046  *      Edges which are connected at both ends but
3047  *      which do not form part of polygon.
3048  *  - 'dangles'
3049  *      Type: array of GEOSGeometry
3050  *      Edges which have one or both ends which are
3051  *      not incident on another edge endpoint
3052  *  - 'invalid_rings'
3053  *      Type: array of GEOSGeometry
3054  *      Edges which form rings which are invalid
3055  *      (e.g. the component lines contain a self-intersection)
3056  *
3057  */
PHP_FUNCTION(GEOSPolygonize)3058 PHP_FUNCTION(GEOSPolygonize)
3059 {
3060     GEOSGeometry *this;
3061     GEOSGeometry *rings;
3062     GEOSGeometry *cut_edges;
3063     GEOSGeometry *dangles;
3064     GEOSGeometry *invalid_rings;
3065     zval *array_elem;
3066     zval *zobj;
3067 
3068     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
3069         == FAILURE)
3070     {
3071         RETURN_NULL();
3072     }
3073     this = getRelay(zobj, Geometry_ce_ptr);
3074 
3075     rings = GEOSPolygonize_full_r(GEOS_G(handle), this, &cut_edges, &dangles, &invalid_rings);
3076     if ( ! rings ) RETURN_NULL(); /* should get an exception first */
3077 
3078     /* return value should be an array */
3079     array_init(return_value);
3080 
3081     MAKE_STD_ZVAL(array_elem);
3082     array_init(array_elem);
3083     dumpGeometry(rings, array_elem);
3084     GEOSGeom_destroy_r(GEOS_G(handle), rings);
3085     GEOS_PHP_ADD_ASSOC_ZVAL(return_value, "rings", array_elem);
3086 
3087     MAKE_STD_ZVAL(array_elem);
3088     array_init(array_elem);
3089     dumpGeometry(cut_edges, array_elem);
3090     GEOSGeom_destroy_r(GEOS_G(handle), cut_edges);
3091     GEOS_PHP_ADD_ASSOC_ZVAL(return_value, "cut_edges", array_elem);
3092 
3093     MAKE_STD_ZVAL(array_elem);
3094     array_init(array_elem);
3095     dumpGeometry(dangles, array_elem);
3096     GEOSGeom_destroy_r(GEOS_G(handle), dangles);
3097     GEOS_PHP_ADD_ASSOC_ZVAL(return_value, "dangles", array_elem);
3098 
3099     MAKE_STD_ZVAL(array_elem);
3100     array_init(array_elem);
3101     dumpGeometry(invalid_rings, array_elem);
3102     GEOSGeom_destroy_r(GEOS_G(handle), invalid_rings);
3103     GEOS_PHP_ADD_ASSOC_ZVAL(return_value, "invalid_rings", array_elem);
3104 
3105 }
3106 
3107 /**
3108  * array GEOSLineMerge(GEOSGeometry $geom)
3109  */
PHP_FUNCTION(GEOSLineMerge)3110 PHP_FUNCTION(GEOSLineMerge)
3111 {
3112     GEOSGeometry *geom_in;
3113     GEOSGeometry *geom_out;
3114     zval *zobj;
3115 
3116     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zobj)
3117         == FAILURE)
3118     {
3119         RETURN_NULL();
3120     }
3121     geom_in = getRelay(zobj, Geometry_ce_ptr);
3122 
3123     geom_out = GEOSLineMerge_r(GEOS_G(handle), geom_in);
3124     if ( ! geom_out ) RETURN_NULL(); /* should get an exception first */
3125 
3126     /* return value should be an array */
3127     array_init(return_value);
3128     dumpGeometry(geom_out, return_value);
3129     GEOSGeom_destroy_r(GEOS_G(handle), geom_out);
3130 }
3131 
3132 /**
3133  * GEOSGeometry GEOSSharedPaths(GEOSGeometry $geom1, GEOSGeometry *geom2)
3134  */
3135 #ifdef HAVE_GEOS_SHARED_PATHS
PHP_FUNCTION(GEOSSharedPaths)3136 PHP_FUNCTION(GEOSSharedPaths)
3137 {
3138     GEOSGeometry *geom_in_1;
3139     GEOSGeometry *geom_in_2;
3140     GEOSGeometry *geom_out;
3141     zval *zobj1, *zobj2;
3142 
3143     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "oo", &zobj1, &zobj2)
3144         == FAILURE)
3145     {
3146         RETURN_NULL();
3147     }
3148     geom_in_1 = getRelay(zobj1, Geometry_ce_ptr);
3149     geom_in_2 = getRelay(zobj2, Geometry_ce_ptr);
3150 
3151     geom_out = GEOSSharedPaths_r(GEOS_G(handle), geom_in_1, geom_in_2);
3152     if ( ! geom_out ) RETURN_NULL(); /* should get an exception first */
3153 
3154     /* return_value is a zval */
3155     object_init_ex(return_value, Geometry_ce_ptr);
3156     setRelay(return_value, geom_out);
3157 }
3158 #endif
3159 
3160 /**
3161  * GEOSGeometry::delaunayTriangulation([<tolerance>], [<onlyEdges>])
3162  *
3163  *  'tolerance'
3164  *       Type: double
3165  *       snapping tolerance to use for improved robustness
3166  *  'onlyEdges'
3167  *       Type: boolean
3168  *       if true will return a MULTILINESTRING, otherwise (the default)
3169  *       it will return a GEOMETRYCOLLECTION containing triangular POLYGONs.
3170  */
3171 #ifdef HAVE_GEOS_DELAUNAY_TRIANGULATION
PHP_METHOD(Geometry,delaunayTriangulation)3172 PHP_METHOD(Geometry, delaunayTriangulation)
3173 {
3174     GEOSGeometry *this;
3175     GEOSGeometry *ret;
3176     double tolerance = 0.0;
3177     zend_bool edgeonly = 0;
3178 
3179     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
3180 
3181     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|db",
3182             &tolerance, &edgeonly) == FAILURE) {
3183         RETURN_NULL();
3184     }
3185 
3186     ret = GEOSDelaunayTriangulation_r(GEOS_G(handle), this, tolerance, edgeonly ? 1 : 0);
3187     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
3188 
3189     /* return_value is a zval */
3190     object_init_ex(return_value, Geometry_ce_ptr);
3191     setRelay(return_value, ret);
3192 }
3193 #endif
3194 
3195 /**
3196  * GEOSGeometry::voronoiDiagram([<tolerance>], [<onlyEdges>], [<extent>])
3197  *
3198  *  'tolerance'
3199  *       Type: double
3200  *       snapping tolerance to use for improved robustness
3201  *  'onlyEdges'
3202  *       Type: boolean
3203  *       if true will return a MULTILINESTRING, otherwise (the default)
3204  *       it will return a GEOMETRYCOLLECTION containing POLYGONs.
3205  *  'extent'
3206  *       Type: geometry
3207  *       Clip returned diagram by the extent of the given geometry
3208  */
3209 #ifdef HAVE_GEOS_VORONOI_DIAGRAM
PHP_METHOD(Geometry,voronoiDiagram)3210 PHP_METHOD(Geometry, voronoiDiagram)
3211 {
3212     GEOSGeometry *this;
3213     GEOSGeometry *ret;
3214     zval *zobj = 0;
3215     GEOSGeometry *env = 0;
3216     double tolerance = 0.0;
3217     zend_bool edgeonly = 0;
3218 
3219     this = (GEOSGeometry*)getRelay(getThis(), Geometry_ce_ptr);
3220 
3221     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|dbo",
3222             &tolerance, &edgeonly, &zobj) == FAILURE) {
3223         RETURN_NULL();
3224     }
3225 
3226     if ( zobj ) env = getRelay(zobj, Geometry_ce_ptr);
3227     ret = GEOSVoronoiDiagram_r(GEOS_G(handle), this, env, tolerance, edgeonly ? 1 : 0);
3228     if ( ! ret ) RETURN_NULL(); /* should get an exception first */
3229 
3230     /* return_value is a zval */
3231     object_init_ex(return_value, Geometry_ce_ptr);
3232     setRelay(return_value, ret);
3233 }
3234 #endif
3235 
3236 /**
3237  * bool GEOSRelateMatch(string matrix, string pattern)
3238  */
3239 #ifdef HAVE_GEOS_RELATE_PATTERN_MATCH
PHP_FUNCTION(GEOSRelateMatch)3240 PHP_FUNCTION(GEOSRelateMatch)
3241 {
3242     char* mat = NULL;
3243     char* pat = NULL;
3244 #if PHP_VERSION_ID >= 70000
3245     size_t matlen;
3246     size_t patlen;
3247 #else
3248     int matlen;
3249     int patlen;
3250 #endif
3251     int ret;
3252     zend_bool retBool;
3253 
3254     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",
3255         &mat, &matlen, &pat, &patlen) == FAILURE)
3256     {
3257         RETURN_NULL();
3258     }
3259 
3260     ret = GEOSRelatePatternMatch_r(GEOS_G(handle), mat, pat);
3261     if ( ret == 2 ) RETURN_NULL(); /* should get an exception first */
3262 
3263     /* return_value is a zval */
3264     retBool = ret;
3265     RETURN_BOOL(retBool);
3266 }
3267 #endif
3268 
3269 /* ------ Initialization / Deinitialization / Meta ------------------ */
3270 
3271 /* per-module initialization */
PHP_MINIT_FUNCTION(geos)3272 PHP_MINIT_FUNCTION(geos)
3273 {
3274     zend_class_entry ce;
3275 
3276     /* WKTReader */
3277     INIT_CLASS_ENTRY(ce, "GEOSWKTReader", WKTReader_methods);
3278     WKTReader_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
3279     WKTReader_ce_ptr->create_object = WKTReader_create_obj;
3280     memcpy(&WKTReader_object_handlers,
3281         zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3282     WKTReader_object_handlers.clone_obj = NULL;
3283 #if PHP_VERSION_ID >= 70000
3284     WKTReader_object_handlers.offset = XtOffsetOf(Proxy, std);
3285     WKTReader_object_handlers.free_obj = WKTReader_dtor;
3286 #endif
3287 
3288     /* WKTWriter */
3289     INIT_CLASS_ENTRY(ce, "GEOSWKTWriter", WKTWriter_methods);
3290     WKTWriter_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
3291     WKTWriter_ce_ptr->create_object = WKTWriter_create_obj;
3292     memcpy(&WKTWriter_object_handlers,
3293         zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3294     WKTWriter_object_handlers.clone_obj = NULL;
3295 #if PHP_VERSION_ID >= 70000
3296     WKTWriter_object_handlers.offset = XtOffsetOf(Proxy, std);
3297     WKTWriter_object_handlers.free_obj = WKTWriter_dtor;
3298 #endif
3299 
3300     /* Geometry */
3301     INIT_CLASS_ENTRY(ce, "GEOSGeometry", Geometry_methods);
3302     Geometry_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
3303     Geometry_ce_ptr->create_object = Geometry_create_obj;
3304     memcpy(&Geometry_object_handlers,
3305         zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3306     Geometry_object_handlers.clone_obj = NULL;
3307     /* Geometry serialization */
3308     Geometry_ce_ptr->serialize = Geometry_serialize;
3309     Geometry_ce_ptr->unserialize = Geometry_deserialize;
3310 #if PHP_VERSION_ID >= 70000
3311     Geometry_object_handlers.offset = XtOffsetOf(Proxy, std);
3312     Geometry_object_handlers.free_obj = Geometry_dtor;
3313 #endif
3314 
3315     /* WKBWriter */
3316     INIT_CLASS_ENTRY(ce, "GEOSWKBWriter", WKBWriter_methods);
3317     WKBWriter_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
3318     WKBWriter_ce_ptr->create_object = WKBWriter_create_obj;
3319     memcpy(&WKBWriter_object_handlers,
3320         zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3321     WKBWriter_object_handlers.clone_obj = NULL;
3322 #if PHP_VERSION_ID >= 70000
3323     WKBWriter_object_handlers.offset = XtOffsetOf(Proxy, std);
3324     WKBWriter_object_handlers.free_obj = WKBWriter_dtor;
3325 #endif
3326 
3327     /* WKBReader */
3328     INIT_CLASS_ENTRY(ce, "GEOSWKBReader", WKBReader_methods);
3329     WKBReader_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
3330     WKBReader_ce_ptr->create_object = WKBReader_create_obj;
3331     memcpy(&WKBReader_object_handlers,
3332         zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3333     WKBReader_object_handlers.clone_obj = NULL;
3334 #if PHP_VERSION_ID >= 70000
3335     WKBReader_object_handlers.offset = XtOffsetOf(Proxy, std);
3336     WKBReader_object_handlers.free_obj = WKBReader_dtor;
3337 #endif
3338 
3339 
3340     /* Constants */
3341     REGISTER_LONG_CONSTANT("GEOSBUF_CAP_ROUND",  GEOSBUF_CAP_ROUND,
3342         CONST_CS|CONST_PERSISTENT);
3343     REGISTER_LONG_CONSTANT("GEOSBUF_CAP_FLAT",   GEOSBUF_CAP_FLAT,
3344         CONST_CS|CONST_PERSISTENT);
3345     REGISTER_LONG_CONSTANT("GEOSBUF_CAP_SQUARE", GEOSBUF_CAP_SQUARE,
3346         CONST_CS|CONST_PERSISTENT);
3347     REGISTER_LONG_CONSTANT("GEOSBUF_JOIN_ROUND", GEOSBUF_JOIN_ROUND,
3348         CONST_CS|CONST_PERSISTENT);
3349     REGISTER_LONG_CONSTANT("GEOSBUF_JOIN_MITRE", GEOSBUF_JOIN_MITRE,
3350         CONST_CS|CONST_PERSISTENT);
3351     REGISTER_LONG_CONSTANT("GEOSBUF_JOIN_BEVEL", GEOSBUF_JOIN_BEVEL,
3352         CONST_CS|CONST_PERSISTENT);
3353 
3354     REGISTER_LONG_CONSTANT("GEOS_POINT", GEOS_POINT,
3355         CONST_CS|CONST_PERSISTENT);
3356     REGISTER_LONG_CONSTANT("GEOS_LINESTRING", GEOS_LINESTRING,
3357         CONST_CS|CONST_PERSISTENT);
3358     REGISTER_LONG_CONSTANT("GEOS_LINEARRING", GEOS_LINEARRING,
3359         CONST_CS|CONST_PERSISTENT);
3360     REGISTER_LONG_CONSTANT("GEOS_POLYGON", GEOS_POLYGON,
3361         CONST_CS|CONST_PERSISTENT);
3362     REGISTER_LONG_CONSTANT("GEOS_MULTIPOINT", GEOS_MULTIPOINT,
3363         CONST_CS|CONST_PERSISTENT);
3364     REGISTER_LONG_CONSTANT("GEOS_MULTILINESTRING", GEOS_MULTILINESTRING,
3365         CONST_CS|CONST_PERSISTENT);
3366     REGISTER_LONG_CONSTANT("GEOS_MULTIPOLYGON", GEOS_MULTIPOLYGON,
3367         CONST_CS|CONST_PERSISTENT);
3368     REGISTER_LONG_CONSTANT("GEOS_GEOMETRYCOLLECTION", GEOS_GEOMETRYCOLLECTION,
3369         CONST_CS|CONST_PERSISTENT);
3370 
3371     REGISTER_LONG_CONSTANT("GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE",
3372         GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE,
3373         CONST_CS|CONST_PERSISTENT);
3374 
3375 #   ifdef HAVE_GEOS_PREC_NO_TOPO
3376     REGISTER_LONG_CONSTANT("GEOS_PREC_NO_TOPO", GEOS_PREC_NO_TOPO,
3377         CONST_CS|CONST_PERSISTENT);
3378 #   endif
3379 
3380 #   ifdef HAVE_GEOS_PREC_KEEP_COLLAPSED
3381     REGISTER_LONG_CONSTANT("GEOS_PREC_KEEP_COLLAPSED", GEOS_PREC_KEEP_COLLAPSED,
3382         CONST_CS|CONST_PERSISTENT);
3383 #   endif
3384 
3385     REGISTER_LONG_CONSTANT("GEOSRELATE_BNR_MOD2", GEOSRELATE_BNR_MOD2,
3386         CONST_CS|CONST_PERSISTENT);
3387     REGISTER_LONG_CONSTANT("GEOSRELATE_BNR_OGC", GEOSRELATE_BNR_OGC,
3388         CONST_CS|CONST_PERSISTENT);
3389     REGISTER_LONG_CONSTANT("GEOSRELATE_BNR_ENDPOINT", GEOSRELATE_BNR_ENDPOINT,
3390         CONST_CS|CONST_PERSISTENT);
3391     REGISTER_LONG_CONSTANT("GEOSRELATE_BNR_MULTIVALENT_ENDPOINT",
3392         GEOSRELATE_BNR_MULTIVALENT_ENDPOINT,
3393         CONST_CS|CONST_PERSISTENT);
3394     REGISTER_LONG_CONSTANT("GEOSRELATE_BNR_MONOVALENT_ENDPOINT",
3395         GEOSRELATE_BNR_MONOVALENT_ENDPOINT,
3396         CONST_CS|CONST_PERSISTENT);
3397 
3398     return SUCCESS;
3399 }
3400 
3401 /* per-module shutdown */
PHP_MSHUTDOWN_FUNCTION(geos)3402 PHP_MSHUTDOWN_FUNCTION(geos)
3403 {
3404     delGeometrySerializer();
3405     delGeometryDeserializer();
3406     return SUCCESS;
3407 }
3408 
3409 /* per-request initialization */
PHP_RINIT_FUNCTION(geos)3410 PHP_RINIT_FUNCTION(geos)
3411 {
3412     GEOS_G(handle) = initGEOS_r(noticeHandler, errorHandler);
3413     return SUCCESS;
3414 }
3415 
3416 /* pre-request destruction */
PHP_RSHUTDOWN_FUNCTION(geos)3417 PHP_RSHUTDOWN_FUNCTION(geos)
3418 {
3419     finishGEOS_r(GEOS_G(handle));
3420     return SUCCESS;
3421 }
3422 
3423 /* global initialization */
PHP_GINIT_FUNCTION(geos)3424 PHP_GINIT_FUNCTION(geos)
3425 {
3426     geos_globals->handle = NULL;
3427 }
3428 
3429 /* module info */
PHP_MINFO_FUNCTION(geos)3430 PHP_MINFO_FUNCTION(geos)
3431 {
3432     php_info_print_table_start();
3433     php_info_print_table_row(2,
3434         "GEOS - Geometry Engine Open Source", "enabled");
3435     php_info_print_table_row(2,
3436         "Version", PHP_GEOS_VERSION);
3437     php_info_print_table_row(2,
3438         "GEOS Version", GEOSversion());
3439     php_info_print_table_end();
3440 }
3441