1 /**********************************************************************
2  * $Id$
3  *
4  * Project:  MapServer
5  * Purpose:  PHP/MapScript extension for MapServer : Utility functions
6  *           Header - macros
7  * Author:   Daniel Morissette, DM Solutions Group (dmorissette@dmsolutions.ca)
8  *
9  **********************************************************************
10  * Copyright (c) 2000, 2001, Daniel Morissette, DM Solutions Group Inc.
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in
20  * all copies of this Software or works derived from this Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
25  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  **********************************************************************/
30 
31 
32 #ifndef PHP_MAPSCRIPT_UTIL_H
33 #define PHP_MAPSCRIPT_UTIL_H
34 
35 #include "php.h"
36 #include "php_globals.h"
37 #include "php_mapscript.h"
38 
39 #if PHP_VERSION_ID < 70000
40 
41 #if ZEND_MODULE_API_NO < 20010901
42 #define TSRMLS_D  void
43 #define TSRMLS_DC
44 #define TSRMLS_C
45 #define TSRMLS_CC
46 #endif
47 
48 /* Add pseudo refcount macros for PHP version < 5.3 */
49 #ifndef Z_REFCOUNT_PP
50 
51 #define Z_REFCOUNT_PP(ppz)        Z_REFCOUNT_P(*(ppz))
52 #define Z_SET_REFCOUNT_PP(ppz, rc)    Z_SET_REFCOUNT_P(*(ppz), rc)
53 #define Z_ADDREF_PP(ppz)        Z_ADDREF_P(*(ppz))
54 #define Z_DELREF_PP(ppz)        Z_DELREF_P(*(ppz))
55 #define Z_ISREF_PP(ppz)         Z_ISREF_P(*(ppz))
56 #define Z_SET_ISREF_PP(ppz)       Z_SET_ISREF_P(*(ppz))
57 #define Z_UNSET_ISREF_PP(ppz)     Z_UNSET_ISREF_P(*(ppz))
58 #define Z_SET_ISREF_TO_PP(ppz, isref) Z_SET_ISREF_TO_P(*(ppz), isref)
59 
60 #define Z_REFCOUNT_P(pz)        zval_refcount_p(pz)
61 #define Z_SET_REFCOUNT_P(pz, rc)    zval_set_refcount_p(pz, rc)
62 #define Z_ADDREF_P(pz)          zval_addref_p(pz)
63 #define Z_DELREF_P(pz)          zval_delref_p(pz)
64 #define Z_ISREF_P(pz)         zval_isref_p(pz)
65 #define Z_SET_ISREF_P(pz)       zval_set_isref_p(pz)
66 #define Z_UNSET_ISREF_P(pz)       zval_unset_isref_p(pz)
67 #define Z_SET_ISREF_TO_P(pz, isref)   zval_set_isref_to_p(pz, isref)
68 
69 #define Z_REFCOUNT(z)         Z_REFCOUNT_P(&(z))
70 #define Z_SET_REFCOUNT(z, rc)     Z_SET_REFCOUNT_P(&(z), rc)
71 #define Z_ADDREF(z)           Z_ADDREF_P(&(z))
72 #define Z_DELREF(z)           Z_DELREF_P(&(z))
73 #define Z_ISREF(z)            Z_ISREF_P(&(z))
74 #define Z_SET_ISREF(z)          Z_SET_ISREF_P(&(z))
75 #define Z_UNSET_ISREF(z)        Z_UNSET_ISREF_P(&(z))
76 #define Z_SET_ISREF_TO(z, isref)    Z_SET_ISREF_TO_P(&(z), isref)
77 
78 #if defined(__GNUC__)
79 #define zend_always_inline inline __attribute__((always_inline))
80 #elif defined(_MSC_VER)
81 #define zend_always_inline __forceinline
82 #else
83 #define zend_always_inline inline
84 #endif
85 
zval_refcount_p(zval * pz)86 static zend_always_inline zend_uint zval_refcount_p(zval* pz)
87 {
88   return pz->refcount;
89 }
90 
zval_set_refcount_p(zval * pz,zend_uint rc)91 static zend_always_inline zend_uint zval_set_refcount_p(zval* pz, zend_uint rc)
92 {
93   return pz->refcount = rc;
94 }
95 
zval_addref_p(zval * pz)96 static zend_always_inline zend_uint zval_addref_p(zval* pz)
97 {
98   return ++pz->refcount;
99 }
100 
zval_delref_p(zval * pz)101 static zend_always_inline zend_uint zval_delref_p(zval* pz)
102 {
103   return --pz->refcount;
104 }
105 
zval_isref_p(zval * pz)106 static zend_always_inline zend_bool zval_isref_p(zval* pz)
107 {
108   return pz->is_ref;
109 }
110 
zval_set_isref_p(zval * pz)111 static zend_always_inline zend_bool zval_set_isref_p(zval* pz)
112 {
113   return pz->is_ref = 1;
114 }
115 
zval_unset_isref_p(zval * pz)116 static zend_always_inline zend_bool zval_unset_isref_p(zval* pz)
117 {
118   return pz->is_ref = 0;
119 }
120 
zval_set_isref_to_p(zval * pz,zend_bool isref)121 static zend_always_inline zend_bool zval_set_isref_to_p(zval* pz, zend_bool isref)
122 {
123   return pz->is_ref = isref;
124 }
125 
126 #endif
127 
128 /* PHP >=5.3 replaced ZVAL_DELREF by Z_DELREF_P */
129 #if ZEND_MODULE_API_NO >= 20090626
130 #define ZVAL_DELREF Z_DELREF_P
131 #define ZVAL_ADDREF Z_ADDREF_P
132 #endif
133 
134 
135 #define MAPSCRIPT_REGISTER_CLASS(name, functions, class_entry, constructor) \
136     INIT_CLASS_ENTRY(ce, name, functions); \
137     class_entry = zend_register_internal_class(&ce TSRMLS_CC); \
138     class_entry->create_object = constructor;
139 
140 #define MAPSCRIPT_ALLOC_OBJECT(zobj, object_type)  \
141     zobj = ecalloc(1, sizeof(object_type));
142 
143 #define MAPSCRIPT_FREE_OBJECT(zobj) \
144     zend_hash_destroy(zobj->std.properties); \
145     FREE_HASHTABLE(zobj->std.properties);
146 #endif /* PHP_VERSION_ID < 70000 */
147 
148 #if PHP_VERSION_ID >= 70300
149 #define MAPSCRIPT_ADDREF(zv) if(!Z_ISUNDEF(zv)) GC_ADDREF(Z_COUNTED(zv))
150 #define MAPSCRIPT_ADDREF_P(p) if(!Z_ISUNDEF(*p)) GC_ADDREF(Z_COUNTED_P(p))
151 #else
152 #if PHP_VERSION_ID >= 70000
153 #define MAPSCRIPT_ADDREF(zv) if(!(Z_ISUNDEF(zv))) GC_REFCOUNT(Z_COUNTED(zv))++;
154 #define MAPSCRIPT_ADDREF_P(zv) if(!(Z_ISUNDEF(*zv))) GC_REFCOUNT(Z_COUNTED_P(zv))++;
155 #else
156 #define MAPSCRIPT_ADDREF(zobj) if (zobj) Z_ADDREF_P(zobj)
157 #define MAPSCRIPT_ADDREF_P(zv) MAPSCRIPT_ADDREF(zv)
158 #endif  /* PHP_VERSION_ID >= 70000 */
159 #endif  /* PHP_VERSION_ID >= 70300 */
160 
161 #if PHP_VERSION_ID >= 70300
162 #define MAPSCRIPT_DELREF(zv)                            \
163     if (!(Z_ISUNDEF(zv)))                               \
164     {                                                   \
165         zend_refcounted *_gc = Z_COUNTED(zv);           \
166         GC_DELREF(_gc);                       \
167         if(GC_REFCOUNT(_gc) == 0)                       \
168             rc_dtor_func(_gc);                          \
169         ZVAL_UNDEF(&zv);                                \
170     }
171 #else
172 #if PHP_VERSION_ID >= 70000
173 #if PHP_VERSION_ID >= 70100
174 #define _zval_dtor_func_for_ptr _zval_dtor_func
175 #endif /* PHP_VERSION_ID >= 70100 */
176 #define MAPSCRIPT_DELREF(zv)                            \
177     if (!(Z_ISUNDEF(zv)))                               \
178     {                                                   \
179 		zend_refcounted *_gc = Z_COUNTED_P(&zv);        \
180 		if(--GC_REFCOUNT(_gc) == 0)                     \
181             _zval_dtor_func_for_ptr(_gc);               \
182         ZVAL_UNDEF(&zv);                                \
183     }
184 #else
185 #define MAPSCRIPT_DELREF(zobj) \
186     if (zobj) \
187     { \
188         if (Z_REFCOUNT_P(zobj) == 1) {    \
189             zval_ptr_dtor(&zobj);       \
190         } \
191         else { \
192             Z_DELREF_P(zobj);  \
193         } \
194         zobj = NULL; \
195     }
196 #endif /* PHP_VERSION_ID >= 70000 */
197 #endif  /* PHP_VERSION_ID >= 70300 */
198 
199 #if PHP_VERSION_ID >= 70000
200 #define MAPSCRIPT_FREE_PARENT(parent) \
201     if (parent.child_ptr) \
202         ZVAL_UNDEF(parent.child_ptr); \
203     MAPSCRIPT_DELREF(parent.val);
204 
205 #define MAPSCRIPT_MAKE_PARENT(zobj, ptr) \
206     if(zobj == NULL) \
207         ZVAL_UNDEF(&parent.val); \
208 	else \
209 	    ZVAL_COPY_VALUE(&parent.val, zobj); \
210     parent.child_ptr = ptr;
211 
212 #define MAPSCRIPT_INIT_PARENT(parent) \
213     ZVAL_UNDEF(&parent.val); \
214     parent.child_ptr = NULL;
215 #else
216 
217 #define MAPSCRIPT_FREE_PARENT(parent) \
218     if (parent.child_ptr) \
219         *parent.child_ptr = NULL; \
220     MAPSCRIPT_DELREF(parent.val);
221 
222 #define MAPSCRIPT_MAKE_PARENT(zobj, ptr)            \
223     parent.val = zobj; \
224     parent.child_ptr = ptr;
225 
226 #define MAPSCRIPT_INIT_PARENT(parent) \
227     parent.val = NULL; \
228     parent.child_ptr = NULL;
229 #endif
230 
231 #if PHP_VERSION_ID >= 70000
232 
233 #define MAPSCRIPT_CALL_METHOD_1(zobj, function_name, retval, arg1) \
234     zend_call_method_with_1_params(&zobj, Z_OBJCE(zobj), NULL, function_name, &retval, arg1);
235 
236 #define MAPSCRIPT_CALL_METHOD_2(zobj, function_name, retval, arg1, arg2) \
237     zend_call_method_with_2_params(&zobj, Z_OBJCE(zobj), NULL, function_name, &retval, arg1, arg2);
238 
239 #define MAPSCRIPT_CALL_METHOD_2_P(zobj, function_name, retval, arg1, arg2) \
240     zend_call_method_with_2_params(zobj, Z_OBJCE_P(zobj), NULL, function_name, &retval, arg1, arg2);
241 
242 #else
243 
244 #define MAPSCRIPT_CALL_METHOD_1(zobj, function_name, retval, arg1) \
245     zend_call_method_with_1_params(&zobj, Z_OBJCE_P(zobj), NULL, function_name, &retval, arg1);
246 
247 #define MAPSCRIPT_CALL_METHOD_2(zobj, function_name, retval, arg1, arg2) \
248     zend_call_method_with_2_params(&zobj, Z_OBJCE_P(zobj), NULL, function_name, &retval, arg1, arg2);
249 
250 #define MAPSCRIPT_CALL_METHOD_2_P(zobj, function_name, retval, arg1, arg2) \
251     MAPSCRIPT_CALL_METHOD_2(zobj, function_name, retval, arg1, arg2)
252 
253 #endif /* PHP_VERSION_ID */
254 
255 #define STRING_EQUAL(string1, string2) \
256     strcmp(string1, string2) == 0
257 
258 /* helpers for getters */
259 #define IF_GET_STRING(property_name, value)  \
260     if (strcmp(property, property_name)==0) \
261     { \
262         MAPSCRIPT_RETVAL_STRING( (value ? value:"") , 1);    \
263     } \
264 
265 #define IF_GET_LONG(property_name, value)  \
266     if (strcmp(property, property_name)==0) \
267     { \
268         RETVAL_LONG(value); \
269     } \
270 
271 #define IF_GET_DOUBLE(property_name, value)  \
272     if (strcmp(property, property_name)==0) \
273     { \
274         RETVAL_DOUBLE(value); \
275     } \
276 
277 #if PHP_VERSION_ID >= 70000
278 #define IF_GET_OBJECT(property_name, mapscript_ce, php_object_storage, internal_object) \
279     if (strcmp(property, property_name)==0)  \
280     {   \
281         if (Z_ISUNDEF(php_object_storage)) {                             \
282             mapscript_fetch_object(mapscript_ce, zobj, NULL, (void*)internal_object, \
283                                    &php_object_storage TSRMLS_CC); \
284         }                                                               \
285         RETURN_ZVAL(&php_object_storage, 1, 0);                          \
286     }
287 #else
288 #define IF_GET_OBJECT(property_name, mapscript_ce, php_object_storage, internal_object) \
289     if (strcmp(property, property_name)==0)  \
290     {   \
291         if (!php_object_storage) {                             \
292             mapscript_fetch_object(mapscript_ce, zobj, NULL, (void*)internal_object, \
293                                    &php_object_storage TSRMLS_CC); \
294         }                                                               \
295         RETURN_ZVAL(php_object_storage, 1, 0);                          \
296     }
297 #endif
298 
299 #if PHP_VERSION_ID >= 70000
300 #define CHECK_OBJECT(mapscript_ce, php_object_storage, internal_object) \
301     if (Z_ISUNDEF(php_object_storage)) {                             \
302         mapscript_fetch_object(mapscript_ce, zobj, NULL, (void*)internal_object, \
303                            &php_object_storage TSRMLS_CC); \
304     }
305 #else
306 #define CHECK_OBJECT(mapscript_ce, php_object_storage, internal_object) \
307     if (!php_object_storage) {                             \
308         mapscript_fetch_object(mapscript_ce, zobj, NULL, (void*)internal_object, \
309                            &php_object_storage TSRMLS_CC); \
310     }
311 #endif
312 
313 /* helpers for setters */
314 #define IF_SET_STRING(property_name, internal, value)        \
315     if (strcmp(property, property_name)==0)                  \
316     { \
317         convert_to_string(value); \
318         if (internal) free(internal);    \
319         if (Z_STRVAL_P(value))                        \
320             internal = msStrdup(Z_STRVAL_P(value));     \
321     }
322 
323 #define IF_SET_LONG(property_name, internal, value)        \
324     if (strcmp(property, property_name)==0)                  \
325     { \
326         convert_to_long(value); \
327         internal = Z_LVAL_P(value);             \
328     }
329 
330 #define IF_SET_DOUBLE(property_name, internal, value)        \
331     if (strcmp(property, property_name)==0)                  \
332     { \
333         convert_to_double(value); \
334         internal = Z_DVAL_P(value);             \
335     }
336 
337 #define IF_SET_BYTE(property_name, internal, value)        \
338     if (strcmp(property, property_name)==0)                  \
339     { \
340         convert_to_long(value); \
341         internal = (unsigned char)Z_LVAL_P(value);            \
342     }
343 
344 #define IF_SET_COLOR(property_name, internal, value)        \
345     if (strcmp(property, property_name)==0)                  \
346     { \
347         convert_to_long(value); \
348         /* validate the color value */ \
349         if (Z_LVAL_P(value) < 0 || Z_LVAL_P(value) > 255) {             \
350             mapscript_throw_exception("Invalid color value. It must be between 0 and 255." TSRMLS_CC); \
351             return;   \
352         }             \
353         internal = Z_LVAL_P(value);             \
354     }
355 
356 #if PHP_VERSION_ID < 70000
357 zend_object_value mapscript_object_new(zend_object *zobj,
358                                        zend_class_entry *ce,
359                                        void (*zend_objects_free_object) TSRMLS_DC);
360 #endif /* PHP_VERSION_ID < 70000 */
361 
362 int mapscript_extract_associative_array(HashTable *php, char **array);
363 
364 #endif /* PHP_MAPSCRIPT_UTIL_H */
365