1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 #include <Properties.h>
6 #include <Util.h>
7 
8 using namespace std;
9 using namespace IcePHP;
10 
11 ZEND_EXTERN_MODULE_GLOBALS(ice)
12 
13 //
14 // Class entries represent the PHP class implementations we have registered.
15 //
16 namespace IcePHP
17 {
18 zend_class_entry* propertiesClassEntry = 0;
19 }
20 
21 //
22 // Properties support.
23 //
24 static zend_object_handlers _handlers;
25 
26 extern "C"
27 {
28 static zend_object_value handleAlloc(zend_class_entry* TSRMLS_DC);
29 static void handleFreeStorage(void* TSRMLS_DC);
30 static zend_object_value handleClone(zval* TSRMLS_DC);
31 }
32 
ZEND_METHOD(Ice_Properties,__construct)33 ZEND_METHOD(Ice_Properties, __construct)
34 {
35     runtimeError("properties objects cannot be instantiated, use createProperties()" TSRMLS_CC);
36 }
37 
ZEND_METHOD(Ice_Properties,__toString)38 ZEND_METHOD(Ice_Properties, __toString)
39 {
40     if(ZEND_NUM_ARGS() > 0)
41     {
42         WRONG_PARAM_COUNT;
43     }
44 
45     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
46     assert(_this);
47 
48     try
49     {
50         Ice::PropertyDict val = _this->getPropertiesForPrefix("");
51         string str;
52         for(Ice::PropertyDict::const_iterator p = val.begin(); p != val.end(); ++p)
53         {
54             if(p != val.begin())
55             {
56                 str.append("\n");
57             }
58             str.append(p->first + "=" + p->second);
59         }
60         RETURN_STRINGL(STRCAST(str.c_str()), static_cast<int>(str.length()), 1);
61     }
62     catch(const IceUtil::Exception& ex)
63     {
64         throwException(ex TSRMLS_CC);
65         RETURN_NULL();
66     }
67 }
68 
ZEND_METHOD(Ice_Properties,getProperty)69 ZEND_METHOD(Ice_Properties, getProperty)
70 {
71     char* name;
72     int nameLen;
73 
74     if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s"), &name, &nameLen) == FAILURE)
75     {
76         RETURN_NULL();
77     }
78 
79     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
80     assert(_this);
81 
82     string propName(name, nameLen);
83     try
84     {
85         string val = _this->getProperty(propName);
86         RETURN_STRINGL(STRCAST(val.c_str()), static_cast<int>(val.length()), 1);
87     }
88     catch(const IceUtil::Exception& ex)
89     {
90         throwException(ex TSRMLS_CC);
91         RETURN_NULL();
92     }
93 }
94 
ZEND_METHOD(Ice_Properties,getPropertyWithDefault)95 ZEND_METHOD(Ice_Properties, getPropertyWithDefault)
96 {
97     char* name;
98     int nameLen;
99     char* def;
100     int defLen;
101 
102     if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("ss!"), &name, &nameLen, &def, &defLen) ==
103         FAILURE)
104     {
105         RETURN_NULL();
106     }
107 
108     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
109     assert(_this);
110 
111     string propName(name, nameLen);
112     string defaultValue;
113     if(def)
114     {
115         defaultValue = string(def, defLen);
116     }
117 
118     try
119     {
120         string val = _this->getPropertyWithDefault(propName, defaultValue);
121         RETURN_STRINGL(STRCAST(val.c_str()), static_cast<int>(val.length()), 1);
122     }
123     catch(const IceUtil::Exception& ex)
124     {
125         throwException(ex TSRMLS_CC);
126         RETURN_NULL();
127     }
128 }
129 
ZEND_METHOD(Ice_Properties,getPropertyAsInt)130 ZEND_METHOD(Ice_Properties, getPropertyAsInt)
131 {
132     char* name;
133     int nameLen;
134 
135     if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s"), &name, &nameLen) == FAILURE)
136     {
137         RETURN_NULL();
138     }
139 
140     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
141     assert(_this);
142 
143     string propName(name, nameLen);
144     try
145     {
146         Ice::Int val = _this->getPropertyAsInt(propName);
147         RETURN_LONG(static_cast<long>(val));
148     }
149     catch(const IceUtil::Exception& ex)
150     {
151         throwException(ex TSRMLS_CC);
152         RETURN_NULL();
153     }
154 }
155 
ZEND_METHOD(Ice_Properties,getPropertyAsIntWithDefault)156 ZEND_METHOD(Ice_Properties, getPropertyAsIntWithDefault)
157 {
158     char* name;
159     int nameLen;
160     long def;
161 
162     if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("sl"), &name, &nameLen, &def) == FAILURE)
163     {
164         RETURN_NULL();
165     }
166 
167     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
168     assert(_this);
169 
170     string propName(name, nameLen);
171     try
172     {
173         Ice::Int val = _this->getPropertyAsIntWithDefault(propName, def);
174         RETURN_LONG(static_cast<long>(val));
175     }
176     catch(const IceUtil::Exception& ex)
177     {
178         throwException(ex TSRMLS_CC);
179         RETURN_NULL();
180     }
181 }
182 
ZEND_METHOD(Ice_Properties,getPropertyAsList)183 ZEND_METHOD(Ice_Properties, getPropertyAsList)
184 {
185     char* name;
186     int nameLen;
187 
188     if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s"), &name, &nameLen) == FAILURE)
189     {
190         RETURN_NULL();
191     }
192 
193     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
194     assert(_this);
195 
196     string propName(name, nameLen);
197     try
198     {
199         Ice::StringSeq val = _this->getPropertyAsList(propName);
200         if(!createStringArray(return_value, val TSRMLS_CC))
201         {
202             RETURN_NULL();
203         }
204     }
205     catch(const IceUtil::Exception& ex)
206     {
207         throwException(ex TSRMLS_CC);
208         RETURN_NULL();
209     }
210 }
211 
ZEND_METHOD(Ice_Properties,getPropertyAsListWithDefault)212 ZEND_METHOD(Ice_Properties, getPropertyAsListWithDefault)
213 {
214     char* name;
215     int nameLen;
216     zval* def;
217 
218     if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("sa!"), &name, &nameLen, &def) == FAILURE)
219     {
220         RETURN_NULL();
221     }
222 
223     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
224     assert(_this);
225 
226     string propName(name, nameLen);
227     Ice::StringSeq defaultValue;
228     if(def && !extractStringArray(def, defaultValue TSRMLS_CC))
229     {
230         RETURN_NULL();
231     }
232 
233     try
234     {
235         Ice::StringSeq val = _this->getPropertyAsListWithDefault(propName, defaultValue);
236         if(!createStringArray(return_value, val TSRMLS_CC))
237         {
238             RETURN_NULL();
239         }
240     }
241     catch(const IceUtil::Exception& ex)
242     {
243         throwException(ex TSRMLS_CC);
244         RETURN_NULL();
245     }
246 }
247 
ZEND_METHOD(Ice_Properties,getPropertiesForPrefix)248 ZEND_METHOD(Ice_Properties, getPropertiesForPrefix)
249 {
250     char* p;
251     int pLen;
252 
253     if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s!"), &p, &pLen) == FAILURE)
254     {
255         RETURN_NULL();
256     }
257 
258     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
259     assert(_this);
260 
261     string prefix;
262     if(p)
263     {
264         prefix = string(p, pLen);
265     }
266 
267     try
268     {
269         Ice::PropertyDict val = _this->getPropertiesForPrefix(prefix);
270         if(!createStringMap(return_value, val TSRMLS_CC))
271         {
272             RETURN_NULL();
273         }
274     }
275     catch(const IceUtil::Exception& ex)
276     {
277         throwException(ex TSRMLS_CC);
278         RETURN_NULL();
279     }
280 }
281 
ZEND_METHOD(Ice_Properties,setProperty)282 ZEND_METHOD(Ice_Properties, setProperty)
283 {
284     char* name;
285     int nameLen;
286     char* val;
287     int valLen;
288 
289     if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("ss!"), &name, &nameLen, &val, &valLen) ==
290         FAILURE)
291     {
292         RETURN_NULL();
293     }
294 
295     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
296     assert(_this);
297 
298     string propName(name, nameLen);
299     string propValue;
300     if(val)
301     {
302         propValue = string(val, valLen);
303     }
304 
305     try
306     {
307         _this->setProperty(propName, propValue);
308     }
309     catch(const IceUtil::Exception& ex)
310     {
311         throwException(ex TSRMLS_CC);
312         RETURN_NULL();
313     }
314 }
315 
ZEND_METHOD(Ice_Properties,getCommandLineOptions)316 ZEND_METHOD(Ice_Properties, getCommandLineOptions)
317 {
318     if(ZEND_NUM_ARGS() != 0)
319     {
320         WRONG_PARAM_COUNT;
321     }
322 
323     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
324     assert(_this);
325 
326     try
327     {
328         Ice::StringSeq val = _this->getCommandLineOptions();
329         if(!createStringArray(return_value, val TSRMLS_CC))
330         {
331             RETURN_NULL();
332         }
333     }
334     catch(const IceUtil::Exception& ex)
335     {
336         throwException(ex TSRMLS_CC);
337         RETURN_NULL();
338     }
339 }
340 
ZEND_METHOD(Ice_Properties,parseCommandLineOptions)341 ZEND_METHOD(Ice_Properties, parseCommandLineOptions)
342 {
343     char* p;
344     int pLen;
345     zval* opts;
346 
347     if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s!a!"), &p, &pLen, &opts) == FAILURE)
348     {
349         RETURN_NULL();
350     }
351 
352     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
353     assert(_this);
354 
355     string prefix;
356     if(p)
357     {
358         prefix = string(p, pLen);
359     }
360     Ice::StringSeq options;
361     if(opts && !extractStringArray(opts, options TSRMLS_CC))
362     {
363         RETURN_NULL();
364     }
365 
366     try
367     {
368         Ice::StringSeq val = _this->parseCommandLineOptions(prefix, options);
369         if(!createStringArray(return_value, val TSRMLS_CC))
370         {
371             RETURN_NULL();
372         }
373     }
374     catch(const IceUtil::Exception& ex)
375     {
376         throwException(ex TSRMLS_CC);
377         RETURN_NULL();
378     }
379 }
380 
ZEND_METHOD(Ice_Properties,parseIceCommandLineOptions)381 ZEND_METHOD(Ice_Properties, parseIceCommandLineOptions)
382 {
383     zval* opts;
384 
385     if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("a!"), &opts) == FAILURE)
386     {
387         RETURN_NULL();
388     }
389 
390     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
391     assert(_this);
392 
393     Ice::StringSeq options;
394     if(opts && !extractStringArray(opts, options TSRMLS_CC))
395     {
396         RETURN_NULL();
397     }
398 
399     try
400     {
401         Ice::StringSeq val = _this->parseIceCommandLineOptions(options);
402         if(!createStringArray(return_value, val TSRMLS_CC))
403         {
404             RETURN_NULL();
405         }
406     }
407     catch(const IceUtil::Exception& ex)
408     {
409         throwException(ex TSRMLS_CC);
410         RETURN_NULL();
411     }
412 }
413 
ZEND_METHOD(Ice_Properties,load)414 ZEND_METHOD(Ice_Properties, load)
415 {
416     char* f;
417     int fLen;
418 
419     if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s"), &f, &fLen) == FAILURE)
420     {
421         RETURN_NULL();
422     }
423 
424     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
425     assert(_this);
426 
427     string file(f, fLen);
428 
429     try
430     {
431         _this->load(file);
432     }
433     catch(const IceUtil::Exception& ex)
434     {
435         throwException(ex TSRMLS_CC);
436         RETURN_NULL();
437     }
438 }
439 
ZEND_METHOD(Ice_Properties,clone)440 ZEND_METHOD(Ice_Properties, clone)
441 {
442     if(ZEND_NUM_ARGS() > 0)
443     {
444         WRONG_PARAM_COUNT;
445     }
446 
447     Ice::PropertiesPtr _this = Wrapper<Ice::PropertiesPtr>::value(getThis() TSRMLS_CC);
448     assert(_this);
449 
450     try
451     {
452         Ice::PropertiesPtr pclone = _this->clone();
453 
454         if(!createProperties(return_value, pclone TSRMLS_CC))
455         {
456             RETURN_NULL();
457         }
458     }
459     catch(const IceUtil::Exception& ex)
460     {
461         throwException(ex TSRMLS_CC);
462         RETURN_NULL();
463     }
464 }
465 
466 #ifdef _WIN32
467 extern "C"
468 #endif
469 static zend_object_value
handleAlloc(zend_class_entry * ce TSRMLS_DC)470 handleAlloc(zend_class_entry* ce TSRMLS_DC)
471 {
472     zend_object_value result;
473 
474     Wrapper<Ice::PropertiesPtr>* obj = Wrapper<Ice::PropertiesPtr>::create(ce TSRMLS_CC);
475     assert(obj);
476 
477     result.handle = zend_objects_store_put(obj, 0, (zend_objects_free_object_storage_t)handleFreeStorage, 0 TSRMLS_CC);
478     result.handlers = &_handlers;
479 
480     return result;
481 }
482 
483 #ifdef _WIN32
484 extern "C"
485 #endif
486 static void
handleFreeStorage(void * p TSRMLS_DC)487 handleFreeStorage(void* p TSRMLS_DC)
488 {
489     Wrapper<Ice::PropertiesPtr>* obj = static_cast<Wrapper<Ice::PropertiesPtr>*>(p);
490     delete obj->ptr;
491     zend_object_std_dtor(static_cast<zend_object*>(p) TSRMLS_CC);
492     efree(p);
493 }
494 
495 #ifdef _WIN32
496 extern "C"
497 #endif
498 static zend_object_value
handleClone(zval * zv TSRMLS_DC)499 handleClone(zval* zv TSRMLS_DC)
500 {
501     zend_object_value result;
502     memset(&result, 0, sizeof(zend_object_value));
503 
504     Ice::PropertiesPtr p = Wrapper<Ice::PropertiesPtr>::value(zv TSRMLS_CC);
505     assert(p);
506 
507     Ice::PropertiesPtr pclone = p->clone();
508 
509     zval* clone;
510     MAKE_STD_ZVAL(clone);
511     if(!createProperties(clone, pclone TSRMLS_CC))
512     {
513         return result;
514     }
515 
516     //
517     // We only need to return the new object's handle, so we must destroy the zval containing
518     // a reference to the new object. We increment the object's reference count to ensure it
519     // does not get destroyed.
520     //
521     result = clone->value.obj;
522     Z_OBJ_HT_P(clone)->add_ref(clone TSRMLS_CC);
523     zval_dtor(clone);
524     efree(clone);
525 
526     return result;
527 }
528 
ZEND_FUNCTION(Ice_createProperties)529 ZEND_FUNCTION(Ice_createProperties)
530 {
531     zval* arglist = 0;
532     zval* defaultsObj = 0;
533 
534     if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("|a!O!"), &arglist, &defaultsObj,
535                              propertiesClassEntry) == FAILURE)
536     {
537         RETURN_NULL();
538     }
539 
540     Ice::StringSeq seq;
541     if(arglist && !extractStringArray(arglist, seq TSRMLS_CC))
542     {
543         RETURN_NULL();
544     }
545 
546     Ice::PropertiesPtr defaults;
547     if(defaultsObj && !fetchProperties(defaultsObj, defaults TSRMLS_CC))
548     {
549         RETURN_NULL();
550     }
551 
552     try
553     {
554         Ice::PropertiesPtr props;
555         if(arglist || defaults)
556         {
557             props = Ice::createProperties(seq, defaults);
558         }
559         else
560         {
561             props = Ice::createProperties();
562         }
563 
564         if(!createProperties(return_value, props TSRMLS_CC))
565         {
566             RETURN_NULL();
567         }
568 
569         if(arglist && PZVAL_IS_REF(arglist))
570         {
571             zval_dtor(arglist);
572             if(!createStringArray(arglist, seq TSRMLS_CC))
573             {
574                 RETURN_NULL();
575             }
576         }
577     }
578     catch(const IceUtil::Exception& ex)
579     {
580         throwException(ex TSRMLS_CC);
581         RETURN_NULL();
582     }
583 }
584 
585 //
586 // Necessary to suppress warnings from zend_function_entry in php-5.2.
587 //
588 #if defined(__GNUC__)
589 #  pragma GCC diagnostic ignored "-Wwrite-strings"
590 #endif
591 
592 //
593 // Predefined methods for Properties.
594 //
595 static zend_function_entry _interfaceMethods[] =
596 {
597     {0, 0, 0}
598 };
599 static zend_function_entry _classMethods[] =
600 {
601     ZEND_ME(Ice_Properties, __construct, ICE_NULLPTR, ZEND_ACC_PRIVATE|ZEND_ACC_CTOR)
602     ZEND_ME(Ice_Properties, __toString, ICE_NULLPTR, ZEND_ACC_PUBLIC)
603     ZEND_ME(Ice_Properties, getProperty, ICE_NULLPTR, ZEND_ACC_PUBLIC)
604     ZEND_ME(Ice_Properties, getPropertyWithDefault, ICE_NULLPTR, ZEND_ACC_PUBLIC)
605     ZEND_ME(Ice_Properties, getPropertyAsInt, ICE_NULLPTR, ZEND_ACC_PUBLIC)
606     ZEND_ME(Ice_Properties, getPropertyAsIntWithDefault, ICE_NULLPTR, ZEND_ACC_PUBLIC)
607     ZEND_ME(Ice_Properties, getPropertyAsList, ICE_NULLPTR, ZEND_ACC_PUBLIC)
608     ZEND_ME(Ice_Properties, getPropertyAsListWithDefault, ICE_NULLPTR, ZEND_ACC_PUBLIC)
609     ZEND_ME(Ice_Properties, getPropertiesForPrefix, ICE_NULLPTR, ZEND_ACC_PUBLIC)
610     ZEND_ME(Ice_Properties, setProperty, ICE_NULLPTR, ZEND_ACC_PUBLIC)
611     ZEND_ME(Ice_Properties, getCommandLineOptions, ICE_NULLPTR, ZEND_ACC_PUBLIC)
612     ZEND_ME(Ice_Properties, parseCommandLineOptions, ICE_NULLPTR, ZEND_ACC_PUBLIC)
613     ZEND_ME(Ice_Properties, parseIceCommandLineOptions, ICE_NULLPTR, ZEND_ACC_PUBLIC)
614     ZEND_ME(Ice_Properties, load, ICE_NULLPTR, ZEND_ACC_PUBLIC)
615     ZEND_ME(Ice_Properties, clone, ICE_NULLPTR, ZEND_ACC_PUBLIC)
616     {0, 0, 0}
617 };
618 
619 //
620 // enable warning again
621 //
622 #if defined(__GNUC__)
623 #  pragma GCC diagnostic error "-Wwrite-strings"
624 #endif
625 
626 bool
propertiesInit(TSRMLS_D)627 IcePHP::propertiesInit(TSRMLS_D)
628 {
629     //
630     // We register an interface and a class that implements the interface. This allows
631     // applications to safely include the Slice-generated code for the type.
632     //
633 
634     //
635     // Register the Properties interface.
636     //
637     zend_class_entry ce;
638 #ifdef ICEPHP_USE_NAMESPACES
639     INIT_NS_CLASS_ENTRY(ce, "Ice", "Properties", _interfaceMethods);
640 #else
641     INIT_CLASS_ENTRY(ce, "Ice_Properties", _interfaceMethods);
642 #endif
643     zend_class_entry* interface = zend_register_internal_interface(&ce TSRMLS_CC);
644 
645     //
646     // Register the Properties class.
647     //
648     INIT_CLASS_ENTRY(ce, "IcePHP_Properties", _classMethods);
649     ce.create_object = handleAlloc;
650     propertiesClassEntry = zend_register_internal_class(&ce TSRMLS_CC);
651     memcpy(&_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
652     _handlers.clone_obj = handleClone;
653     zend_class_implements(propertiesClassEntry TSRMLS_CC, 1, interface);
654 
655     return true;
656 }
657 
658 bool
createProperties(zval * zv,const Ice::PropertiesPtr & p TSRMLS_DC)659 IcePHP::createProperties(zval* zv, const Ice::PropertiesPtr& p TSRMLS_DC)
660 {
661     if(object_init_ex(zv, propertiesClassEntry) != SUCCESS)
662     {
663         runtimeError("unable to initialize properties object" TSRMLS_CC);
664         return false;
665     }
666 
667     Wrapper<Ice::PropertiesPtr>* obj = Wrapper<Ice::PropertiesPtr>::extract(zv TSRMLS_CC);
668     assert(!obj->ptr);
669     obj->ptr = new Ice::PropertiesPtr(p);
670 
671     return true;
672 }
673 
674 bool
fetchProperties(zval * zv,Ice::PropertiesPtr & p TSRMLS_DC)675 IcePHP::fetchProperties(zval* zv, Ice::PropertiesPtr& p TSRMLS_DC)
676 {
677     if(!ZVAL_IS_NULL(zv))
678     {
679         if(Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != propertiesClassEntry)
680         {
681             invalidArgument("value is not a properties object" TSRMLS_CC);
682             return false;
683         }
684         p = Wrapper<Ice::PropertiesPtr>::value(zv TSRMLS_CC);
685         if(!p)
686         {
687             runtimeError("unable to retrieve properties object from object store" TSRMLS_CC);
688             return false;
689         }
690     }
691     return true;
692 }
693