1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4
5 #include <Types.h>
6 #include <Proxy.h>
7 #include <Util.h>
8 #include <IceUtil/InputUtil.h>
9 #include <IceUtil/OutputUtil.h>
10 #include <IceUtil/ScopedArray.h>
11 #include <Slice/PHPUtil.h>
12 #include <Ice/SlicedData.h>
13
14 #include <limits>
15
16 using namespace std;
17 using namespace IcePHP;
18 using namespace IceUtil;
19 using namespace IceUtilInternal;
20
21 ZEND_EXTERN_MODULE_GLOBALS(ice)
22
23 //
24 // Class entries represent the PHP class implementations we have registered.
25 //
26 namespace IcePHP
27 {
28 zend_class_entry* typeInfoClassEntry = 0;
29 zend_class_entry* exceptionInfoClassEntry = 0;
30 }
31
32 static zend_object_handlers _typeInfoHandlers;
33 static zend_object_handlers _exceptionInfoHandlers;
34
35 static string _unsetGUID = "710A52F2-A014-4CB2-AF40-348D48DBCDDD";
36
37 extern "C"
38 {
39 static zend_object* handleTypeInfoAlloc(zend_class_entry*);
40 static void handleTypeInfoFreeStorage(zend_object*);
41
42 static zend_object* handleExceptionInfoAlloc(zend_class_entry*);
43 static void handleExceptionInfoFreeStorage(zend_object*);
44 }
45
46 typedef map<string, ProxyInfoPtr> ProxyInfoMap;
47 typedef map<string, ClassInfoPtr> ClassInfoMap;
48 typedef map<Ice::Int, ClassInfoPtr> CompactIdMap;
49 typedef map<string, ExceptionInfoPtr> ExceptionInfoMap;
50
51 //
52 // addProxyInfo()
53 //
54 static void
addProxyInfo(const ProxyInfoPtr & p)55 addProxyInfo(const ProxyInfoPtr& p)
56 {
57 ProxyInfoMap* m;
58 if(ICE_G(proxyInfoMap))
59 {
60 m = reinterpret_cast<ProxyInfoMap*>(ICE_G(proxyInfoMap));
61 }
62 else
63 {
64 m = new ProxyInfoMap;
65 ICE_G(proxyInfoMap) = m;
66 }
67 m->insert(ProxyInfoMap::value_type(p->id, p));
68 }
69
70 //
71 // getProxyInfo()
72 //
73 IcePHP::ProxyInfoPtr
getProxyInfo(const string & id)74 IcePHP::getProxyInfo(const string& id)
75 {
76 if(ICE_G(proxyInfoMap))
77 {
78 ProxyInfoMap* m = reinterpret_cast<ProxyInfoMap*>(ICE_G(proxyInfoMap));
79 ProxyInfoMap::iterator p = m->find(id);
80 if(p != m->end())
81 {
82 return p->second;
83 }
84 }
85 return 0;
86 }
87
88 //
89 // addClassInfoById()
90 //
91 static void
addClassInfoById(const ClassInfoPtr & p)92 addClassInfoById(const ClassInfoPtr& p)
93 {
94 assert(!getClassInfoById(p->id));
95
96 ClassInfoMap* m = reinterpret_cast<ClassInfoMap*>(ICE_G(idToClassInfoMap));
97 if(!m)
98 {
99 m = new ClassInfoMap;
100 ICE_G(idToClassInfoMap) = m;
101 }
102 m->insert(ClassInfoMap::value_type(p->id, p));
103 }
104
105 //
106 // addClassInfoByName()
107 //
108 static void
addClassInfoByName(const ClassInfoPtr & p)109 addClassInfoByName(const ClassInfoPtr& p)
110 {
111 assert(!getClassInfoByName(p->name));
112 #ifdef ICEPHP_USE_NAMESPACES
113 assert(p->name[0] == '\\');
114 #endif
115
116 ClassInfoMap* m = reinterpret_cast<ClassInfoMap*>(ICE_G(nameToClassInfoMap));
117 if(!m)
118 {
119 m = new ClassInfoMap;
120 ICE_G(nameToClassInfoMap) = m;
121 }
122 m->insert(ClassInfoMap::value_type(p->name, p));
123 }
124
125 static ClassInfoPtr
getClassInfoByClass(zend_class_entry * cls,zend_class_entry * formal)126 getClassInfoByClass(zend_class_entry* cls, zend_class_entry* formal)
127 {
128 //
129 // See if there's a match in our class name => ClassInfo map.
130 //
131 ClassInfoPtr info = getClassInfoByName(cls->name->val);
132
133 //
134 // Check the base class, assuming it's compatible with our formal type (if any).
135 //
136 if(!info && cls->parent && (!formal || checkClass(cls->parent, formal)))
137 {
138 info = getClassInfoByClass(cls->parent, formal);
139 }
140
141 //
142 // Check interfaces.
143 //
144 if(!info)
145 {
146 for(zend_ulong i = 0; i < cls->num_interfaces && !info; ++i)
147 {
148 if(!formal || checkClass(cls->interfaces[i], formal))
149 {
150 info = getClassInfoByClass(cls->interfaces[i], formal);
151 }
152 }
153 }
154
155 return info;
156 }
157
158 //
159 // getClassInfoById()
160 //
161 IcePHP::ClassInfoPtr
getClassInfoById(const string & id)162 IcePHP::getClassInfoById(const string& id)
163 {
164 if(ICE_G(idToClassInfoMap))
165 {
166 ClassInfoMap* m = reinterpret_cast<ClassInfoMap*>(ICE_G(idToClassInfoMap));
167 ClassInfoMap::iterator p = m->find(id);
168 if(p != m->end())
169 {
170 return p->second;
171 }
172 }
173 return 0;
174 }
175
176 //
177 // getClassInfoByName()
178 //
179 IcePHP::ClassInfoPtr
getClassInfoByName(const string & name)180 IcePHP::getClassInfoByName(const string& name)
181 {
182 if(ICE_G(nameToClassInfoMap))
183 {
184 string s = name;
185
186 #ifdef ICEPHP_USE_NAMESPACES
187 //
188 // PHP's class definition (zend_class_entry) does not use a leading backslash
189 // in the class name.
190 //
191 if(s[0] != '\\')
192 {
193 s.insert(0, "\\");
194 }
195 #endif
196
197 ClassInfoMap* m = reinterpret_cast<ClassInfoMap*>(ICE_G(nameToClassInfoMap));
198 ClassInfoMap::iterator p = m->find(s);
199 if(p != m->end())
200 {
201 return p->second;
202 }
203 }
204 return 0;
205 }
206
207 //
208 // getExceptionInfo()
209 //
210 IcePHP::ExceptionInfoPtr
getExceptionInfo(const string & id)211 IcePHP::getExceptionInfo(const string& id)
212 {
213 if(ICE_G(exceptionInfoMap))
214 {
215 ExceptionInfoMap* m = reinterpret_cast<ExceptionInfoMap*>(ICE_G(exceptionInfoMap));
216 ExceptionInfoMap::iterator p = m->find(id);
217 if(p != m->end())
218 {
219 return p->second;
220 }
221 }
222 return 0;
223 }
224
225 //
226 // StreamUtil implementation
227 //
228 zend_class_entry* IcePHP::StreamUtil::_slicedDataType = 0;
229 zend_class_entry* IcePHP::StreamUtil::_sliceInfoType = 0;
230
~StreamUtil()231 IcePHP::StreamUtil::~StreamUtil()
232 {
233 //
234 // Make sure we break any cycles among the ObjectReaders in preserved slices.
235 //
236 for(set<ObjectReaderPtr>::iterator p = _readers.begin(); p != _readers.end(); ++p)
237 {
238 Ice::SlicedDataPtr slicedData = (*p)->getSlicedData();
239 for(Ice::SliceInfoSeq::const_iterator q = slicedData->slices.begin(); q != slicedData->slices.end(); ++q)
240 {
241 //
242 // Don't just call (*q)->instances.clear(), as releasing references
243 // to the instances could have unexpected side effects. We exchange
244 // the vector into a temporary and then let the temporary fall out
245 // of scope.
246 //
247 vector<Ice::ObjectPtr> tmp;
248 tmp.swap((*q)->instances);
249 }
250 }
251 }
252
253 void
add(const ReadObjectCallbackPtr & callback)254 IcePHP::StreamUtil::add(const ReadObjectCallbackPtr& callback)
255 {
256 _callbacks.push_back(callback);
257 }
258
259 void
add(const ObjectReaderPtr & reader)260 IcePHP::StreamUtil::add(const ObjectReaderPtr& reader)
261 {
262 assert(reader->getSlicedData());
263 _readers.insert(reader);
264 }
265
266 void
updateSlicedData(void)267 IcePHP::StreamUtil::updateSlicedData(void)
268 {
269 for(set<ObjectReaderPtr>::iterator p = _readers.begin(); p != _readers.end(); ++p)
270 {
271 setSlicedDataMember((*p)->getObject(), (*p)->getSlicedData());
272 }
273 }
274
275 void
setSlicedDataMember(zval * obj,const Ice::SlicedDataPtr & slicedData)276 IcePHP::StreamUtil::setSlicedDataMember(zval* obj, const Ice::SlicedDataPtr& slicedData)
277 {
278 //
279 // Create a PHP equivalent of the SlicedData object.
280 //
281
282 assert(slicedData);
283
284 if(!_slicedDataType)
285 {
286 _slicedDataType = idToClass("::Ice::SlicedData");
287 assert(_slicedDataType);
288 }
289 if(!_sliceInfoType)
290 {
291 _sliceInfoType = idToClass("::Ice::SliceInfo");
292 assert(_sliceInfoType);
293 }
294
295 zval sd;
296 AutoDestroy sdDestroyer(&sd);
297
298 if(object_init_ex(&sd, _slicedDataType) != SUCCESS)
299 {
300 throw AbortMarshaling();
301 }
302
303 zval slices;
304 array_init(&slices);
305 #ifdef HT_ALLOW_COW_VIOLATION
306 HT_ALLOW_COW_VIOLATION(Z_ARRVAL(slices)); // Allow circular references.
307 #endif
308 AutoDestroy slicesDestroyer(&slices);
309
310 if(add_property_zval(&sd, STRCAST("slices"), &slices) != SUCCESS)
311 {
312 throw AbortMarshaling();
313 }
314
315 //
316 // Translate each SliceInfo object into its PHP equivalent.
317 //
318 for(vector<Ice::SliceInfoPtr>::const_iterator p = slicedData->slices.begin(); p != slicedData->slices.end(); ++p)
319 {
320 zval slice;
321 AutoDestroy sliceDestroyer(&slice);
322
323 if(object_init_ex(&slice, _sliceInfoType) != SUCCESS)
324 {
325 throw AbortMarshaling();
326 }
327
328 add_next_index_zval(&slices, &slice); // Steals a reference.
329 Z_ADDREF_P(&slice);
330
331 //
332 // typeId
333 //
334 zval typeId;
335 AutoDestroy typeIdDestroyer(&typeId);
336 ZVAL_STRINGL(&typeId, STRCAST((*p)->typeId.c_str()), static_cast<int>((*p)->typeId.size()));
337 if(add_property_zval(&slice, STRCAST("typeId"), &typeId) != SUCCESS)
338 {
339 throw AbortMarshaling();
340 }
341
342 //
343 // compactId
344 //
345 zval compactId;
346 AutoDestroy compactIdDestroyer(&compactId);
347 ZVAL_LONG(&compactId, (*p)->compactId);
348 if(add_property_zval(&slice, STRCAST("compactId"), &compactId) != SUCCESS)
349 {
350 throw AbortMarshaling();
351 }
352
353 //
354 // bytes
355 //
356 zval bytes;
357 array_init(&bytes);
358 AutoDestroy bytesDestroyer(&bytes);
359 for(vector<Ice::Byte>::const_iterator q = (*p)->bytes.begin(); q != (*p)->bytes.end(); ++q)
360 {
361 add_next_index_long(&bytes, *q & 0xff);
362 }
363 if(add_property_zval(&slice, STRCAST("bytes"), &bytes) != SUCCESS)
364 {
365 throw AbortMarshaling();
366 }
367
368 //
369 // instances
370 //
371 zval instances;
372 array_init(&instances);
373 #ifdef HT_ALLOW_COW_VIOLATION
374 HT_ALLOW_COW_VIOLATION(Z_ARRVAL(instances)); // Allow circular references.
375 #endif
376 AutoDestroy instancesDestroyer(&instances);
377 if(add_property_zval(&slice, STRCAST("instances"), &instances) != SUCCESS)
378 {
379 throw AbortMarshaling();
380 }
381
382 for(vector<Ice::ObjectPtr>::const_iterator q = (*p)->instances.begin(); q != (*p)->instances.end(); ++q)
383 {
384 //
385 // Each element in the instances list is an instance of ObjectReader that wraps a PHP object.
386 //
387 assert(*q);
388 ObjectReaderPtr r = ObjectReaderPtr::dynamicCast(*q);
389 assert(r);
390 zval* o = r->getObject();
391 assert(Z_TYPE_P(o) == IS_OBJECT); // Should be non-nil.
392 add_next_index_zval(&instances, o); // Steals a reference.
393 Z_ADDREF_P(o);
394 }
395
396 //
397 // hasOptionalMembers
398 //
399 zval hasOptionalMembers;
400 AutoDestroy hasOptionalMembersDestroyer(&hasOptionalMembers);
401 ZVAL_BOOL(&hasOptionalMembers, (*p)->hasOptionalMembers ? 1 : 0);
402 if(add_property_zval(&slice, STRCAST("hasOptionalMembers"), &hasOptionalMembers) != SUCCESS)
403 {
404 throw AbortMarshaling();
405 }
406
407 //
408 // isLastSlice
409 //
410 zval isLastSlice;
411 AutoDestroy isLastSliceDestroyer(&isLastSlice);
412 ZVAL_BOOL(&isLastSlice, (*p)->isLastSlice ? 1 : 0);
413 if(add_property_zval(&slice, STRCAST("isLastSlice"), &isLastSlice) != SUCCESS)
414 {
415 throw AbortMarshaling();
416 }
417 }
418
419 if(add_property_zval(obj, STRCAST("_ice_slicedData"), &sd) != SUCCESS)
420 {
421 throw AbortMarshaling();
422 }
423 }
424
425 //
426 // Instances of preserved class and exception types may have a data member
427 // named _ice_slicedData which is an instance of the PHP class Ice_SlicedData.
428 //
429 Ice::SlicedDataPtr
getSlicedDataMember(zval * obj,ObjectMap * objectMap)430 IcePHP::StreamUtil::getSlicedDataMember(zval* obj, ObjectMap* objectMap)
431 {
432 Ice::SlicedDataPtr slicedData;
433
434 string name = "_ice_slicedData";
435 zval* sd = zend_hash_str_find(Z_OBJPROP_P(obj), STRCAST(name.c_str()), name.size());
436 if(sd)
437 {
438 if(Z_TYPE_P(sd) != IS_NULL)
439 {
440 //
441 // The "slices" member is an array of Ice_SliceInfo objects.
442 //
443
444 zval* sl = zend_hash_str_find(Z_OBJPROP_P(sd), STRCAST("slices"), sizeof("slices") - 1);
445 assert(sl);
446 assert(Z_TYPE_P(sl) == IS_INDIRECT);
447 sl = Z_INDIRECT_P(sl);
448 assert(Z_TYPE_P(sl) == IS_ARRAY);
449
450 Ice::SliceInfoSeq slices;
451
452 HashTable* arr = Z_ARRVAL_P(sl);
453 assert(arr);
454
455 zval* s;
456
457 ZEND_HASH_FOREACH_VAL(arr, s)
458 {
459 assert(Z_OBJCE_P(s) == _sliceInfoType);
460
461 Ice::SliceInfoPtr info = new Ice::SliceInfo;
462
463 zval* typeId = zend_hash_str_find(Z_OBJPROP_P(s), STRCAST("typeId"), sizeof("typeId") - 1);
464 assert(Z_TYPE_P(typeId) == IS_INDIRECT);
465 typeId = Z_INDIRECT_P(typeId);
466 assert(typeId && Z_TYPE_P(typeId) == IS_STRING);
467 info->typeId = string(Z_STRVAL_P(typeId), Z_STRLEN_P(typeId));
468
469 zval* compactId = zend_hash_str_find(Z_OBJPROP_P(s), STRCAST("compactId"), sizeof("compactId") - 1);
470 assert(Z_TYPE_P(compactId) == IS_INDIRECT);
471 compactId = Z_INDIRECT_P(compactId);
472 assert(compactId && Z_TYPE_P(compactId) == IS_LONG);
473 info->compactId = static_cast<long>(Z_LVAL_P(compactId));
474
475 zval* bytes = zend_hash_str_find(Z_OBJPROP_P(s), STRCAST("bytes"), sizeof("bytes") - 1);
476 assert(Z_TYPE_P(bytes) == IS_INDIRECT);
477 bytes = Z_INDIRECT_P(bytes);
478 assert(bytes && Z_TYPE_P(bytes) == IS_ARRAY);
479 HashTable* barr = Z_ARRVAL_P(bytes);
480 zval* e;
481 info->bytes.resize(zend_hash_num_elements(barr));
482
483 #if defined(__clang__)
484 # pragma clang diagnostic push
485 # pragma clang diagnostic ignored "-Wshadow"
486 #endif
487 vector<Ice::Byte>::size_type i = 0;
488 ZEND_HASH_FOREACH_VAL(barr, e)
489 {
490 long l = static_cast<long>(Z_LVAL_P(e));
491 assert(l >= 0 && l <= 255);
492 info->bytes[i++] = static_cast<Ice::Byte>(l);
493 }
494 ZEND_HASH_FOREACH_END();
495 #if defined(__clang__)
496 # pragma clang diagnostic pop
497 #endif
498
499 zval* instances = zend_hash_str_find(Z_OBJPROP_P(s), STRCAST("instances"), sizeof("instances") - 1);
500 assert(Z_TYPE_P(instances) == IS_INDIRECT);
501 instances = Z_INDIRECT_P(instances);
502 assert(instances && Z_TYPE_P(instances) == IS_ARRAY);
503 HashTable* oarr = Z_ARRVAL_P(instances);
504 zval* o;
505
506 #if defined(__clang__)
507 # pragma clang diagnostic push
508 # pragma clang diagnostic ignored "-Wshadow"
509 #endif
510 ZEND_HASH_FOREACH_VAL(oarr, o)
511 {
512 assert(Z_TYPE_P(o) == IS_OBJECT);
513
514 Ice::ObjectPtr writer;
515
516 ObjectMap::iterator i = objectMap->find(Z_OBJ_HANDLE_P(o));
517 if(i == objectMap->end())
518 {
519 writer = new ObjectWriter(o, objectMap, 0);
520 objectMap->insert(ObjectMap::value_type(Z_OBJ_HANDLE_P(o), writer));
521 }
522 else
523 {
524 writer = i->second;
525 }
526
527 info->instances.push_back(writer);
528 }
529 ZEND_HASH_FOREACH_END();
530 #if defined(__clang__)
531 # pragma clang diagnostic pop
532 #endif
533
534 zval* hasOptionalMembers =
535 zend_hash_str_find(Z_OBJPROP_P(s), STRCAST("hasOptionalMembers"), sizeof("hasOptionalMembers") - 1);
536 assert(Z_TYPE_P(hasOptionalMembers) == IS_INDIRECT);
537 hasOptionalMembers = Z_INDIRECT_P(hasOptionalMembers);
538 assert(hasOptionalMembers &&
539 (Z_TYPE_P(hasOptionalMembers) == IS_TRUE || Z_TYPE_P(hasOptionalMembers) == IS_FALSE));
540 info->hasOptionalMembers = Z_TYPE_P(hasOptionalMembers) == IS_TRUE;
541
542 zval* isLastSlice =
543 zend_hash_str_find(Z_OBJPROP_P(s), STRCAST("isLastSlice"), sizeof("isLastSlice") - 1);
544 assert(Z_TYPE_P(isLastSlice) == IS_INDIRECT);
545 isLastSlice = Z_INDIRECT_P(isLastSlice);
546 assert(isLastSlice && (Z_TYPE_P(isLastSlice) == IS_TRUE || Z_TYPE_P(isLastSlice) == IS_FALSE));
547 info->isLastSlice = Z_TYPE_P(isLastSlice) == IS_TRUE;
548
549 slices.push_back(info);
550 }
551 ZEND_HASH_FOREACH_END();
552
553 slicedData = new Ice::SlicedData(slices);
554 }
555 }
556
557 return slicedData;
558 }
559
560 //
561 // UnmarshalCallback implementation.
562 //
~UnmarshalCallback()563 IcePHP::UnmarshalCallback::~UnmarshalCallback()
564 {
565 }
566
567 //
568 // TypeInfo implementation.
569 //
TypeInfo()570 IcePHP::TypeInfo::TypeInfo()
571 {
572 }
573
574 bool
usesClasses() const575 IcePHP::TypeInfo::usesClasses() const
576 {
577 return false;
578 }
579
580 void
unmarshaled(zval *,zval *,void *)581 IcePHP::TypeInfo::unmarshaled(zval*, zval*, void*)
582 {
583 assert(false);
584 }
585
586 void
destroy()587 IcePHP::TypeInfo::destroy()
588 {
589 }
590
591 //
592 // PrimitiveInfo implementation.
593 //
594 string
getId() const595 IcePHP::PrimitiveInfo::getId() const
596 {
597 switch(kind)
598 {
599 case KindBool:
600 return "bool";
601 case KindByte:
602 return "byte";
603 case KindShort:
604 return "short";
605 case KindInt:
606 return "int";
607 case KindLong:
608 return "long";
609 case KindFloat:
610 return "float";
611 case KindDouble:
612 return "double";
613 case KindString:
614 return "string";
615 }
616 assert(false);
617 return string();
618 }
619
620 bool
validate(zval * zv,bool throwException)621 IcePHP::PrimitiveInfo::validate(zval* zv, bool throwException)
622 {
623 switch(kind)
624 {
625 case PrimitiveInfo::KindBool:
626 {
627 if(!(Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE))
628 {
629 string s = zendTypeToString(Z_TYPE_P(zv));
630 if(throwException)
631 {
632 invalidArgument("expected boolean value but received %s", s.c_str());
633 }
634 return false;
635 }
636 break;
637 }
638 case PrimitiveInfo::KindByte:
639 {
640 if(Z_TYPE_P(zv) != IS_LONG)
641 {
642 string s = zendTypeToString(Z_TYPE_P(zv));
643 if(throwException)
644 {
645 invalidArgument("expected byte value but received %s", s.c_str());
646 }
647 return false;
648 }
649 long val = static_cast<long>(Z_LVAL_P(zv));
650 if(val < 0 || val > 255)
651 {
652 if(throwException)
653 {
654 invalidArgument("value %ld is out of range for a byte", val);
655 }
656 return false;
657 }
658 break;
659 }
660 case PrimitiveInfo::KindShort:
661 {
662 if(Z_TYPE_P(zv) != IS_LONG)
663 {
664 string s = zendTypeToString(Z_TYPE_P(zv));
665 if(throwException)
666 {
667 invalidArgument("expected short value but received %s", s.c_str());
668 }
669 return false;
670 }
671 zend_long val = Z_LVAL_P(zv);
672 if(val < SHRT_MIN || val > SHRT_MAX)
673 {
674 if(throwException)
675 {
676 invalidArgument("value %ld is out of range for a short", val);
677 }
678 return false;
679 }
680 break;
681 }
682 case PrimitiveInfo::KindInt:
683 {
684 if(Z_TYPE_P(zv) != IS_LONG)
685 {
686 string s = zendTypeToString(Z_TYPE_P(zv));
687 if(throwException)
688 {
689 invalidArgument("expected int value but received %s", s.c_str());
690 }
691 return false;
692 }
693 zend_long val = Z_LVAL_P(zv);
694 if(val < INT_MIN || val > INT_MAX)
695 {
696 if(throwException)
697 {
698 invalidArgument("value %ld is out of range for an int", val);
699 }
700 return false;
701 }
702 break;
703 }
704 case PrimitiveInfo::KindLong:
705 {
706 //
707 // The platform's 'long' type may not be 64 bits, so we also accept
708 // a string argument for this type.
709 //
710 if(Z_TYPE_P(zv) != IS_LONG && Z_TYPE_P(zv) != IS_STRING)
711 {
712 string s = zendTypeToString(Z_TYPE_P(zv));
713 if(throwException)
714 {
715 invalidArgument("expected long value but received %s", s.c_str());
716 }
717 return false;
718 }
719
720 if(Z_TYPE_P(zv) != IS_LONG)
721 {
722 Ice::Long val;
723 string sval(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
724 if(!IceUtilInternal::stringToInt64(sval, val))
725 {
726 if(throwException)
727 {
728 invalidArgument("invalid long value `%s'", Z_STRVAL_P(zv));
729 }
730 return false;
731 }
732 }
733 break;
734 }
735 case PrimitiveInfo::KindFloat:
736 {
737 if(Z_TYPE_P(zv) != IS_DOUBLE && Z_TYPE_P(zv) != IS_LONG)
738 {
739 string s = zendTypeToString(Z_TYPE_P(zv));
740 if(throwException)
741 {
742 invalidArgument("expected float value but received %s", s.c_str());
743 }
744 return false;
745 }
746 if(Z_TYPE_P(zv) == IS_DOUBLE)
747 {
748 double val = Z_DVAL_P(zv);
749 return (val <= numeric_limits<float>::max() && val >= -numeric_limits<float>::max()) || !isfinite(val);
750 }
751 break;
752 }
753 case PrimitiveInfo::KindDouble:
754 {
755 if(Z_TYPE_P(zv) != IS_DOUBLE && Z_TYPE_P(zv) != IS_LONG)
756 {
757 string s = zendTypeToString(Z_TYPE_P(zv));
758 if(throwException)
759 {
760 invalidArgument("expected double value but received %s", s.c_str());
761 }
762 return false;
763 }
764 break;
765 }
766 case PrimitiveInfo::KindString:
767 {
768 if(Z_TYPE_P(zv) != IS_STRING && Z_TYPE_P(zv) != IS_NULL)
769 {
770 string s = zendTypeToString(Z_TYPE_P(zv));
771 if(throwException)
772 {
773 invalidArgument("expected string value but received %s", s.c_str());
774 }
775 return false;
776 }
777 break;
778 }
779 }
780
781 return true;
782 }
783
784 bool
variableLength() const785 IcePHP::PrimitiveInfo::variableLength() const
786 {
787 return kind == KindString;
788 }
789
790 int
wireSize() const791 IcePHP::PrimitiveInfo::wireSize() const
792 {
793 switch(kind)
794 {
795 case KindBool:
796 case KindByte:
797 return 1;
798 case KindShort:
799 return 2;
800 case KindInt:
801 return 4;
802 case KindLong:
803 return 8;
804 case KindFloat:
805 return 4;
806 case KindDouble:
807 return 8;
808 case KindString:
809 return 1;
810 }
811 assert(false);
812 return 0;
813 }
814
815 Ice::OptionalFormat
optionalFormat() const816 IcePHP::PrimitiveInfo::optionalFormat() const
817 {
818 switch(kind)
819 {
820 case KindBool:
821 case KindByte:
822 return Ice::OptionalFormatF1;
823 case KindShort:
824 return Ice::OptionalFormatF2;
825 case KindInt:
826 return Ice::OptionalFormatF4;
827 case KindLong:
828 return Ice::OptionalFormatF8;
829 case KindFloat:
830 return Ice::OptionalFormatF4;
831 case KindDouble:
832 return Ice::OptionalFormatF8;
833 case KindString:
834 return Ice::OptionalFormatVSize;
835 }
836
837 assert(false);
838 return Ice::OptionalFormatF1;
839 }
840
841 void
marshal(zval * zv,Ice::OutputStream * os,ObjectMap *,bool)842 IcePHP::PrimitiveInfo::marshal(zval* zv, Ice::OutputStream* os, ObjectMap*, bool)
843 {
844 switch(kind)
845 {
846 case PrimitiveInfo::KindBool:
847 {
848 assert(Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE);
849 os->write(Z_TYPE_P(zv) == IS_TRUE);
850 break;
851 }
852 case PrimitiveInfo::KindByte:
853 {
854 assert(Z_TYPE_P(zv) == IS_LONG);
855 long val = static_cast<long>(Z_LVAL_P(zv));
856 assert(val >= 0 && val <= 255); // validate() should have caught this.
857 os->write(static_cast<Ice::Byte>(val));
858 break;
859 }
860 case PrimitiveInfo::KindShort:
861 {
862 assert(Z_TYPE_P(zv) == IS_LONG);
863 long val = static_cast<long>(Z_LVAL_P(zv));
864 assert(val >= SHRT_MIN && val <= SHRT_MAX); // validate() should have caught this.
865 os->write(static_cast<Ice::Short>(val));
866 break;
867 }
868 case PrimitiveInfo::KindInt:
869 {
870 assert(Z_TYPE_P(zv) == IS_LONG);
871 long val = static_cast<long>(Z_LVAL_P(zv));
872 assert(val >= INT_MIN && val <= INT_MAX); // validate() should have caught this.
873 os->write(static_cast<Ice::Int>(val));
874 break;
875 }
876 case PrimitiveInfo::KindLong:
877 {
878 //
879 // The platform's 'long' type may not be 64 bits, so we also accept
880 // a string argument for this type.
881 //
882 assert(Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_STRING); // validate() should have caught this.
883 Ice::Long val;
884 if(Z_TYPE_P(zv) == IS_LONG)
885 {
886 val = static_cast<long>(Z_LVAL_P(zv));
887 }
888 else
889 {
890 string sval(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
891 IceUtilInternal::stringToInt64(sval, val);
892 }
893 os->write(val);
894 break;
895 }
896 case PrimitiveInfo::KindFloat:
897 {
898 Ice::Double val = 0;
899 if(Z_TYPE_P(zv) == IS_DOUBLE)
900 {
901 val = Z_DVAL_P(zv);
902 }
903 else if(Z_TYPE_P(zv) == IS_LONG)
904 {
905 val = static_cast<double>(Z_LVAL_P(zv));
906 }
907 else
908 {
909 assert(false); // validate() should have caught this.
910 }
911 os->write(static_cast<Ice::Float>(val));
912 break;
913 }
914 case PrimitiveInfo::KindDouble:
915 {
916 Ice::Double val = 0;
917 if(Z_TYPE_P(zv) == IS_DOUBLE)
918 {
919 val = Z_DVAL_P(zv);
920 }
921 else if(Z_TYPE_P(zv) == IS_LONG)
922 {
923 val = static_cast<double>(Z_LVAL_P(zv));
924 }
925 else
926 {
927 assert(false); // validate() should have caught this.
928 }
929 os->write(val);
930 break;
931 }
932 case PrimitiveInfo::KindString:
933 {
934 assert(Z_TYPE_P(zv) == IS_STRING || Z_TYPE_P(zv) == IS_NULL); // validate() should have caught this.
935 if(Z_TYPE_P(zv) == IS_STRING)
936 {
937 string val(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
938 os->write(val);
939 }
940 else
941 {
942 os->write(string());
943 }
944 break;
945 }
946 }
947 }
948
949 void
unmarshal(Ice::InputStream * is,const UnmarshalCallbackPtr & cb,const CommunicatorInfoPtr &,zval * target,void * closure,bool)950 IcePHP::PrimitiveInfo::unmarshal(Ice::InputStream* is, const UnmarshalCallbackPtr& cb,
951 const CommunicatorInfoPtr&, zval* target, void* closure, bool)
952 {
953 zval zv;
954 AutoDestroy destroy(&zv);
955
956 switch(kind)
957 {
958 case PrimitiveInfo::KindBool:
959 {
960 bool val;
961 is->read(val);
962 ZVAL_BOOL(&zv, val ? 1 : 0);
963 break;
964 }
965 case PrimitiveInfo::KindByte:
966 {
967 Ice::Byte val;
968 is->read(val);
969 ZVAL_LONG(&zv, val & 0xff);
970 break;
971 }
972 case PrimitiveInfo::KindShort:
973 {
974 Ice::Short val;
975 is->read(val);
976 ZVAL_LONG(&zv, val);
977 break;
978 }
979 case PrimitiveInfo::KindInt:
980 {
981 Ice::Int val;
982 is->read(val);
983 ZVAL_LONG(&zv, val);
984 break;
985 }
986 case PrimitiveInfo::KindLong:
987 {
988 Ice::Long val;
989 is->read(val);
990
991 //
992 // The platform's 'long' type may not be 64 bits, so we store 64-bit
993 // values as a string.
994 //
995 if(sizeof(Ice::Long) > sizeof(long) && (val < LONG_MIN || val > LONG_MAX))
996 {
997 string str = IceUtilInternal::int64ToString(val);
998 ZVAL_STRINGL(&zv, STRCAST(str.c_str()), static_cast<int>(str.length()));
999 }
1000 else
1001 {
1002 ZVAL_LONG(&zv, static_cast<long>(val));
1003 }
1004 break;
1005 }
1006 case PrimitiveInfo::KindFloat:
1007 {
1008 Ice::Float val;
1009 is->read(val);
1010 ZVAL_DOUBLE(&zv, val);
1011 break;
1012 }
1013 case PrimitiveInfo::KindDouble:
1014 {
1015 Ice::Double val;
1016 is->read(val);
1017 ZVAL_DOUBLE(&zv, val);
1018 break;
1019 }
1020 case PrimitiveInfo::KindString:
1021 {
1022 string val;
1023 is->read(val);
1024 ZVAL_STRINGL(&zv, STRCAST(val.c_str()), static_cast<int>(val.length()));
1025 break;
1026 }
1027 }
1028 cb->unmarshaled(&zv, target, closure);
1029 }
1030
1031 void
print(zval * zv,IceUtilInternal::Output & out,PrintObjectHistory *)1032 IcePHP::PrimitiveInfo::print(zval* zv, IceUtilInternal::Output& out, PrintObjectHistory*)
1033 {
1034 if(!validate(zv, false))
1035 {
1036 out << "<invalid value - expected " << getId() << ">";
1037 return;
1038 }
1039 zval tmp;
1040 ZVAL_STR(&tmp, zval_get_string(zv));
1041 out << Z_STRVAL(tmp);
1042 }
1043
1044 //
1045 // EnumInfo implementation.
1046 //
EnumInfo(const string & ident,zval * en)1047 IcePHP::EnumInfo::EnumInfo(const string& ident, zval* en) :
1048 id(ident),
1049 maxValue(0)
1050 {
1051 HashTable* arr = Z_ARRVAL_P(en);
1052 HashPosition pos;
1053 zval* val;
1054
1055 zend_hash_internal_pointer_reset_ex(arr, &pos);
1056 while((val = zend_hash_get_current_data_ex(arr, &pos)) != 0)
1057 {
1058 assert(Z_TYPE_P(val) == IS_STRING);
1059 string name = Z_STRVAL_P(val);
1060 zend_hash_move_forward_ex(arr, &pos);
1061
1062 val = zend_hash_get_current_data_ex(arr, &pos);
1063 assert(Z_TYPE_P(val) == IS_LONG);
1064 Ice::Int value = static_cast<Ice::Int>(Z_LVAL_P(val));
1065 zend_hash_move_forward_ex(arr, &pos);
1066
1067 if(value > maxValue)
1068 {
1069 const_cast<int&>(maxValue) = value;
1070 }
1071
1072 const_cast<map<Ice::Int, string>&>(enumerators)[value] = name;
1073 }
1074 }
1075
1076 string
getId() const1077 IcePHP::EnumInfo::getId() const
1078 {
1079 return id;
1080 }
1081
1082 bool
validate(zval * zv,bool)1083 IcePHP::EnumInfo::validate(zval* zv, bool)
1084 {
1085 if(Z_TYPE_P(zv) == IS_LONG)
1086 {
1087 const Ice::Int l = static_cast<Ice::Int>(Z_LVAL_P(zv));
1088 return l >= 0 && enumerators.find(l) != enumerators.end();
1089 }
1090 return false;
1091 }
1092
1093 bool
variableLength() const1094 IcePHP::EnumInfo::variableLength() const
1095 {
1096 return true;
1097 }
1098
1099 int
wireSize() const1100 IcePHP::EnumInfo::wireSize() const
1101 {
1102 return 1;
1103 }
1104
1105 Ice::OptionalFormat
optionalFormat() const1106 IcePHP::EnumInfo::optionalFormat() const
1107 {
1108 return Ice::OptionalFormatSize;
1109 }
1110
1111 void
marshal(zval * zv,Ice::OutputStream * os,ObjectMap *,bool)1112 IcePHP::EnumInfo::marshal(zval* zv, Ice::OutputStream* os, ObjectMap*, bool)
1113 {
1114 assert(Z_TYPE_P(zv) == IS_LONG); // validate() should have caught this.
1115 const Ice::Int val = static_cast<Ice::Int>(Z_LVAL_P(zv));
1116 assert(val >= 0 && enumerators.find(val) != enumerators.end()); // validate() should have caught this.
1117
1118 os->writeEnum(val, maxValue);
1119 }
1120
1121 void
unmarshal(Ice::InputStream * is,const UnmarshalCallbackPtr & cb,const CommunicatorInfoPtr &,zval * target,void * closure,bool)1122 IcePHP::EnumInfo::unmarshal(Ice::InputStream* is, const UnmarshalCallbackPtr& cb,
1123 const CommunicatorInfoPtr&, zval* target, void* closure, bool)
1124 {
1125 zval zv;
1126 AutoDestroy destroy(&zv);
1127
1128 const Ice::Int val = is->readEnum(maxValue);
1129
1130 if(enumerators.find(val) == enumerators.end())
1131 {
1132 invalidArgument("enumerator %d is out of range for enum %s", val, id.c_str());
1133 throw AbortMarshaling();
1134 }
1135
1136 ZVAL_LONG(&zv, val);
1137 cb->unmarshaled(&zv, target, closure);
1138 }
1139
1140 void
print(zval * zv,IceUtilInternal::Output & out,PrintObjectHistory *)1141 IcePHP::EnumInfo::print(zval* zv, IceUtilInternal::Output& out, PrintObjectHistory*)
1142 {
1143 if(!validate(zv, false))
1144 {
1145 out << "<invalid value - expected " << id << ">";
1146 return;
1147 }
1148 const Ice::Int val = static_cast<Ice::Int>(Z_LVAL_P(zv));
1149 map<Ice::Int, string>::const_iterator p = enumerators.find(val);
1150 assert(p != enumerators.end());
1151 out << p->second;
1152 }
1153
1154 //
1155 // DataMember implementation.
1156 //
1157 void
unmarshaled(zval * zv,zval * target,void *)1158 IcePHP::DataMember::unmarshaled(zval* zv, zval* target, void*)
1159 {
1160 setMember(target, zv);
1161 }
1162
1163 void
setMember(zval * target,zval * zv)1164 IcePHP::DataMember::setMember(zval* target, zval* zv)
1165 {
1166 assert(Z_TYPE_P(target) == IS_OBJECT);
1167
1168 zend_update_property(Z_OBJCE_P(target), target, STRCAST(name.c_str()), strlen(name.c_str()), zv);
1169 }
1170
1171 static void
convertDataMembers(zval * zv,DataMemberList & reqMembers,DataMemberList & optMembers,bool allowOptional)1172 convertDataMembers(zval* zv, DataMemberList& reqMembers, DataMemberList& optMembers, bool allowOptional)
1173 {
1174 list<DataMemberPtr> optList;
1175
1176 assert(Z_TYPE_P(zv) == IS_ARRAY);
1177 HashTable* membersArray = Z_ARRVAL_P(zv);
1178 zval* arr;
1179
1180 ZEND_HASH_FOREACH_VAL(membersArray, arr)
1181 {
1182 DataMemberPtr m = new DataMember();
1183 zval* elem;
1184
1185 assert(Z_TYPE_P(arr) == IS_ARRAY);
1186 HashTable* member = Z_ARRVAL_P(arr);
1187 assert(zend_hash_num_elements(member) == static_cast<uint32_t>(allowOptional ? 4 : 2));
1188
1189 elem = zend_hash_index_find(member, 0);
1190 assert(Z_TYPE_P(elem) == IS_STRING);
1191 m->name = Z_STRVAL_P(elem);
1192
1193 elem = zend_hash_index_find(member, 1);
1194 assert(Z_TYPE_P(elem) == IS_OBJECT);
1195 m->type = Wrapper<TypeInfoPtr>::value(elem);
1196
1197 if(allowOptional)
1198 {
1199 elem = zend_hash_index_find(member, 2);
1200 assert(Z_TYPE_P(elem) == IS_TRUE || Z_TYPE_P(elem) == IS_FALSE);
1201 m->optional = Z_TYPE_P(elem) == IS_TRUE;
1202
1203 elem = zend_hash_index_find(member, 3);
1204 assert(Z_TYPE_P(elem) == IS_LONG);
1205 m->tag = static_cast<int>(Z_LVAL_P(elem));
1206 }
1207 else
1208 {
1209 m->optional = false;
1210 m->tag = 0;
1211 }
1212
1213 if(m->optional)
1214 {
1215 optList.push_back(m);
1216 }
1217 else
1218 {
1219 reqMembers.push_back(m);
1220 }
1221 }
1222 ZEND_HASH_FOREACH_END();
1223
1224 if(allowOptional)
1225 {
1226 class SortFn
1227 {
1228 public:
1229 static bool compare(const DataMemberPtr& lhs, const DataMemberPtr& rhs)
1230 {
1231 return lhs->tag < rhs->tag;
1232 }
1233 };
1234
1235 optList.sort(SortFn::compare);
1236 copy(optList.begin(), optList.end(), back_inserter(optMembers));
1237 }
1238 }
1239
1240 //
1241 // StructInfo implementation.
1242 //
StructInfo(const string & ident,const string & n,zval * m)1243 IcePHP::StructInfo::StructInfo(const string& ident, const string& n, zval* m) :
1244 id(ident), name(n)
1245 {
1246 // Set to undefined
1247 ZVAL_UNDEF(&_nullMarshalValue);
1248
1249 DataMemberList opt;
1250 convertDataMembers(m, const_cast<DataMemberList&>(members), opt, false);
1251 assert(opt.empty());
1252 const_cast<zend_class_entry*&>(zce) = nameToClass(name);
1253 assert(zce);
1254
1255 _variableLength = false;
1256 _wireSize = 0;
1257 for(DataMemberList::const_iterator p = members.begin(); p != members.end(); ++p)
1258 {
1259 if(!_variableLength && (*p)->type->variableLength())
1260 {
1261 _variableLength = true;
1262 }
1263 _wireSize += (*p)->type->wireSize();
1264 }
1265 }
1266
1267 string
getId() const1268 IcePHP::StructInfo::getId() const
1269 {
1270 return id;
1271 }
1272
1273 bool
validate(zval * zv,bool throwException)1274 IcePHP::StructInfo::validate(zval* zv, bool throwException)
1275 {
1276 if(Z_TYPE_P(zv) == IS_NULL)
1277 {
1278 return true;
1279 }
1280 else if(Z_TYPE_P(zv) != IS_OBJECT)
1281 {
1282 if(throwException)
1283 {
1284 string s = zendTypeToString(Z_TYPE_P(zv));
1285 invalidArgument("expected struct value of type %s but received %s", zce->name->val, s.c_str());
1286 }
1287 return false;
1288 }
1289
1290 //
1291 // Compare class entries.
1292 //
1293 zend_class_entry* ce = Z_OBJCE_P(zv);
1294 if(ce != zce)
1295 {
1296 invalidArgument("expected struct value of type %s but received %s", zce->name->val, ce->name->val);
1297 return false;
1298 }
1299
1300 return true;
1301 }
1302
1303 bool
variableLength() const1304 IcePHP::StructInfo::variableLength() const
1305 {
1306 return _variableLength;
1307 }
1308
1309 int
wireSize() const1310 IcePHP::StructInfo::wireSize() const
1311 {
1312 return _wireSize;
1313 }
1314
1315 Ice::OptionalFormat
optionalFormat() const1316 IcePHP::StructInfo::optionalFormat() const
1317 {
1318 return _variableLength ? Ice::OptionalFormatFSize : Ice::OptionalFormatVSize;
1319 }
1320
1321 bool
usesClasses() const1322 IcePHP::StructInfo::usesClasses() const
1323 {
1324 for(DataMemberList::const_iterator p = members.begin(); p != members.end(); ++p)
1325 {
1326 if((*p)->type->usesClasses())
1327 {
1328 return true;
1329 }
1330 }
1331
1332 return false;
1333 }
1334
1335 void
marshal(zval * zv,Ice::OutputStream * os,ObjectMap * objectMap,bool optional)1336 IcePHP::StructInfo::marshal(zval* zv, Ice::OutputStream* os, ObjectMap* objectMap, bool optional)
1337 {
1338 assert(Z_TYPE_P(zv) == IS_NULL || (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zce));
1339
1340 if(Z_TYPE_P(zv) == IS_NULL)
1341 {
1342 if(Z_ISUNDEF(_nullMarshalValue))
1343 {
1344 if(object_init_ex(&_nullMarshalValue, const_cast<zend_class_entry*>(zce)) != SUCCESS)
1345 {
1346 runtimeError("unable to initialize object of type %s", zce->name->val);
1347 throw AbortMarshaling();
1348 }
1349
1350 if(!invokeMethod(&_nullMarshalValue, ZEND_CONSTRUCTOR_FUNC_NAME))
1351 {
1352 assert(false);
1353 }
1354 }
1355 assert(!Z_ISUNDEF(_nullMarshalValue));
1356 ZVAL_COPY_VALUE(zv, &_nullMarshalValue);
1357 }
1358
1359 Ice::OutputStream::size_type sizePos = 0;
1360 if(optional)
1361 {
1362 if(_variableLength)
1363 {
1364 sizePos = os->startSize();
1365 }
1366 else
1367 {
1368 os->writeSize(_wireSize);
1369 }
1370 }
1371
1372 for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
1373 {
1374 DataMemberPtr member = *q;
1375
1376 zval* val = zend_hash_str_find(Z_OBJPROP_P(zv), STRCAST(member->name.c_str()), member->name.size());
1377 if(!val)
1378 {
1379 runtimeError("member `%s' of %s is not defined", member->name.c_str(), id.c_str());
1380 throw AbortMarshaling();
1381 }
1382
1383 if(Z_TYPE_P(val) == IS_INDIRECT)
1384 {
1385 val = Z_INDIRECT_P(val);
1386 }
1387
1388 if(!member->type->validate(val, false))
1389 {
1390 invalidArgument("invalid value for %s member `%s'", id.c_str(), member->name.c_str());
1391 throw AbortMarshaling();
1392 }
1393
1394 member->type->marshal(val, os, objectMap, false);
1395 }
1396
1397 if(optional && _variableLength)
1398 {
1399 os->endSize(sizePos);
1400 }
1401 }
1402
1403 void
unmarshal(Ice::InputStream * is,const UnmarshalCallbackPtr & cb,const CommunicatorInfoPtr & comm,zval * target,void * closure,bool optional)1404 IcePHP::StructInfo::unmarshal(Ice::InputStream* is, const UnmarshalCallbackPtr& cb,
1405 const CommunicatorInfoPtr& comm, zval* target, void* closure, bool optional)
1406 {
1407 zval zv;
1408 AutoDestroy destroy(&zv);
1409 if(object_init_ex(&zv, const_cast<zend_class_entry*>(zce)) != SUCCESS)
1410 {
1411 runtimeError("unable to initialize object of type %s", zce->name->val);
1412 throw AbortMarshaling();
1413 }
1414
1415 if(optional)
1416 {
1417 if(_variableLength)
1418 {
1419 is->skip(4);
1420 }
1421 else
1422 {
1423 is->skipSize();
1424 }
1425 }
1426
1427 for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
1428 {
1429 DataMemberPtr member = *q;
1430 member->type->unmarshal(is, member, comm, &zv, 0, false);
1431 }
1432
1433 cb->unmarshaled(&zv, target, closure);
1434 }
1435
1436 void
print(zval * zv,IceUtilInternal::Output & out,PrintObjectHistory * history)1437 IcePHP::StructInfo::print(zval* zv, IceUtilInternal::Output& out, PrintObjectHistory* history)
1438 {
1439 if(!validate(zv, false))
1440 {
1441 out << "<invalid value - expected " << id << ">";
1442 return;
1443 }
1444
1445 if(Z_TYPE_P(zv) == IS_NULL)
1446 {
1447 out << "<nil>";
1448 }
1449 else
1450 {
1451 out.sb();
1452 for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
1453 {
1454 DataMemberPtr member = *q;
1455
1456 out << nl << member->name << " = ";
1457 zval* val = zend_hash_str_find(Z_OBJPROP_P(zv), STRCAST(member->name.c_str()), member->name.size());
1458 assert(Z_TYPE_P(val) == IS_INDIRECT);
1459 val = Z_INDIRECT_P(val);
1460 if(val)
1461 {
1462 member->type->print(val, out, history);
1463 }
1464 else
1465 {
1466 out << "<not defined>";
1467 }
1468 }
1469 out.eb();
1470 }
1471 }
1472
1473 void
destroy()1474 IcePHP::StructInfo::destroy()
1475 {
1476 for(DataMemberList::const_iterator p = members.begin(); p != members.end(); ++p)
1477 {
1478 (*p)->type->destroy();
1479 }
1480 const_cast<DataMemberList&>(members).clear();
1481 if(!Z_ISUNDEF(_nullMarshalValue))
1482 {
1483 zval_ptr_dtor(&_nullMarshalValue);
1484 }
1485 }
1486
1487 //
1488 // SequenceInfo implementation.
1489 //
SequenceInfo(const string & ident,zval * e)1490 IcePHP::SequenceInfo::SequenceInfo(const string& ident, zval* e) :
1491 id(ident)
1492 {
1493 const_cast<TypeInfoPtr&>(elementType) = Wrapper<TypeInfoPtr>::value(e);
1494 }
1495
1496 string
getId() const1497 IcePHP::SequenceInfo::getId() const
1498 {
1499 return id;
1500 }
1501
1502 bool
validate(zval * zv,bool)1503 IcePHP::SequenceInfo::validate(zval* zv, bool)
1504 {
1505 return Z_TYPE_P(zv) == IS_NULL || Z_TYPE_P(zv) == IS_ARRAY;
1506 }
1507
1508 bool
variableLength() const1509 IcePHP::SequenceInfo::variableLength() const
1510 {
1511 return true;
1512 }
1513
1514 int
wireSize() const1515 IcePHP::SequenceInfo::wireSize() const
1516 {
1517 return 1;
1518 }
1519
1520 Ice::OptionalFormat
optionalFormat() const1521 IcePHP::SequenceInfo::optionalFormat() const
1522 {
1523 return elementType->variableLength() ? Ice::OptionalFormatFSize : Ice::OptionalFormatVSize;
1524 }
1525
1526 bool
usesClasses() const1527 IcePHP::SequenceInfo::usesClasses() const
1528 {
1529 return elementType->usesClasses();
1530 }
1531
1532 void
marshal(zval * zv,Ice::OutputStream * os,ObjectMap * objectMap,bool optional)1533 IcePHP::SequenceInfo::marshal(zval* zv, Ice::OutputStream* os, ObjectMap* objectMap, bool optional)
1534 {
1535 Ice::Int sz = 0;
1536 HashTable* arr = 0;
1537
1538 if(Z_TYPE_P(zv) != IS_NULL)
1539 {
1540 assert(Z_TYPE_P(zv) == IS_ARRAY); // validate() should have caught this.
1541 arr = Z_ARRVAL_P(zv);
1542 sz = static_cast<Ice::Int>(zend_hash_num_elements(arr));
1543 }
1544
1545 Ice::OutputStream::size_type sizePos = 0;
1546 if(optional)
1547 {
1548 if(elementType->variableLength())
1549 {
1550 sizePos = os->startSize();
1551 }
1552 else if(elementType->wireSize() > 1)
1553 {
1554 os->writeSize(sz == 0 ? 1 : sz * elementType->wireSize() + (sz > 254 ? 5 : 1));
1555 }
1556 }
1557
1558 if(sz == 0)
1559 {
1560 os->writeSize(0);
1561 }
1562 else
1563 {
1564 PrimitiveInfoPtr pi = PrimitiveInfoPtr::dynamicCast(elementType);
1565 if(pi)
1566 {
1567 marshalPrimitiveSequence(pi, zv, os);
1568 return;
1569 }
1570
1571 os->writeSize(sz);
1572
1573 zval* val;
1574 ZEND_HASH_FOREACH_VAL(arr, val)
1575 {
1576 if(!elementType->validate(val, false))
1577 {
1578 invalidArgument("invalid value for sequence element `%s'", id.c_str());
1579 throw AbortMarshaling();
1580 }
1581 elementType->marshal(val, os, objectMap, false);
1582 }
1583 ZEND_HASH_FOREACH_END();
1584 }
1585
1586 if(optional && elementType->variableLength())
1587 {
1588 os->endSize(sizePos);
1589 }
1590 }
1591
1592 void
unmarshal(Ice::InputStream * is,const UnmarshalCallbackPtr & cb,const CommunicatorInfoPtr & comm,zval * target,void * closure,bool optional)1593 IcePHP::SequenceInfo::unmarshal(Ice::InputStream* is, const UnmarshalCallbackPtr& cb,
1594 const CommunicatorInfoPtr& comm, zval* target, void* closure, bool optional)
1595 {
1596 if(optional)
1597 {
1598 if(elementType->variableLength())
1599 {
1600 is->skip(4);
1601 }
1602 else if(elementType->wireSize() > 1)
1603 {
1604 is->skipSize();
1605 }
1606 }
1607
1608 PrimitiveInfoPtr pi = PrimitiveInfoPtr::dynamicCast(elementType);
1609 if(pi)
1610 {
1611 unmarshalPrimitiveSequence(pi, is, cb, target, closure);
1612 return;
1613 }
1614
1615 zval zv;
1616 array_init(&zv);
1617 #ifdef HT_ALLOW_COW_VIOLATION
1618 HT_ALLOW_COW_VIOLATION(Z_ARRVAL(zv)); // Allow circular references.
1619 #endif
1620 AutoDestroy destroy(&zv);
1621
1622 Ice::Int sz = is->readSize();
1623 for(Ice::Int i = 0; i < sz; ++i)
1624 {
1625 #ifdef _MSC_VER
1626 # pragma warning(disable:4311)
1627 # pragma warning(disable:4312)
1628 #endif
1629 void* cl = reinterpret_cast<void*>(i);
1630 #ifdef _MSC_VER
1631 # pragma warning(default:4311)
1632 # pragma warning(default:4312)
1633 #endif
1634 //
1635 // Add a temporary null value so that the foreach order is the
1636 // same as the index order.
1637 //
1638 add_index_null(&zv, i);
1639 elementType->unmarshal(is, this, comm, &zv, cl, false);
1640 }
1641
1642 cb->unmarshaled(&zv, target, closure);
1643 }
1644
1645 void
print(zval * zv,IceUtilInternal::Output & out,PrintObjectHistory * history)1646 IcePHP::SequenceInfo::print(zval* zv, IceUtilInternal::Output& out, PrintObjectHistory* history)
1647 {
1648 if(!validate(zv, false))
1649 {
1650 out << "<invalid value - expected " << id << ">";
1651 return;
1652 }
1653
1654 if(Z_TYPE_P(zv) == IS_NULL)
1655 {
1656 out << "{}";
1657 }
1658 else
1659 {
1660 assert(Z_TYPE_P(zv) == IS_ARRAY);
1661
1662 HashTable* arr = Z_ARRVAL_P(zv);
1663
1664 out.sb();
1665
1666 int i = 0;
1667 zval* val;
1668 ZEND_HASH_FOREACH_VAL(arr, val)
1669 {
1670 out << nl << '[' << i << "] = ";
1671 elementType->print(val, out, history);
1672 ++i;
1673 }
1674 ZEND_HASH_FOREACH_END();
1675
1676 out.eb();
1677 }
1678 }
1679
1680 void
unmarshaled(zval * zv,zval * target,void * closure)1681 IcePHP::SequenceInfo::unmarshaled(zval* zv, zval* target, void* closure)
1682 {
1683 assert(Z_TYPE_P(target) != IS_REFERENCE);
1684 assert(Z_TYPE_P(target) == IS_ARRAY);
1685
1686 #ifdef _MSC_VER
1687 # pragma warning(disable:4302)
1688 # pragma warning(disable:4311)
1689 #endif
1690 long i = reinterpret_cast<long>(closure);
1691 #ifdef _MSC_VER
1692 # pragma warning(default:4302)
1693 # pragma warning(disable:4311)
1694 #endif
1695 add_index_zval(target, i, zv);
1696 if(Z_REFCOUNTED_P(zv))
1697 {
1698 Z_ADDREF_P(zv);
1699 }
1700 }
1701
1702 void
destroy()1703 IcePHP::SequenceInfo::destroy()
1704 {
1705 if(elementType)
1706 {
1707 elementType->destroy();
1708 const_cast<TypeInfoPtr&>(elementType) = 0;
1709 }
1710 }
1711
1712 void
marshalPrimitiveSequence(const PrimitiveInfoPtr & pi,zval * zv,Ice::OutputStream * os)1713 IcePHP::SequenceInfo::marshalPrimitiveSequence(const PrimitiveInfoPtr& pi, zval* zv, Ice::OutputStream* os)
1714 {
1715 HashTable* arr = Z_ARRVAL_P(zv);
1716
1717 Ice::Int sz = static_cast<Ice::Int>(zend_hash_num_elements(arr));
1718 assert(sz > 0);
1719
1720 switch(pi->kind)
1721 {
1722 case PrimitiveInfo::KindBool:
1723 {
1724 Ice::BoolSeq seq(sz);
1725 Ice::Int i = 0;
1726 zval* val;
1727 ZEND_HASH_FOREACH_VAL(arr, val)
1728 {
1729 if(!pi->validate(val, true))
1730 {
1731 throw AbortMarshaling();
1732 }
1733 seq[i++] = Z_TYPE_P(val) == IS_TRUE;
1734 }
1735 ZEND_HASH_FOREACH_END();
1736 os->write(seq);
1737 break;
1738 }
1739 case PrimitiveInfo::KindByte:
1740 {
1741 Ice::ByteSeq seq(sz);
1742 Ice::Int i = 0;
1743 zval* val;
1744 ZEND_HASH_FOREACH_VAL(arr, val)
1745 {
1746 if(!pi->validate(val, true))
1747 {
1748 throw AbortMarshaling();
1749 }
1750 long l = static_cast<long>(Z_LVAL_P(val));
1751 assert(l >= 0 && l <= 255);
1752 seq[i++] = static_cast<Ice::Byte>(l);
1753 }
1754 ZEND_HASH_FOREACH_END();
1755
1756 os->write(&seq[0], &seq[0] + seq.size());
1757 break;
1758 }
1759 case PrimitiveInfo::KindShort:
1760 {
1761 Ice::ShortSeq seq(sz);
1762 Ice::Int i = 0;
1763 zval* val;
1764 ZEND_HASH_FOREACH_VAL(arr, val)
1765 {
1766 if(!pi->validate(val, true))
1767 {
1768 throw AbortMarshaling();
1769 }
1770 long l = static_cast<long>(Z_LVAL_P(val));
1771 assert(l >= SHRT_MIN && l <= SHRT_MAX);
1772 seq[i++] = static_cast<Ice::Short>(l);
1773 }
1774 ZEND_HASH_FOREACH_END();
1775
1776 os->write(&seq[0], &seq[0] + seq.size());
1777 break;
1778 }
1779 case PrimitiveInfo::KindInt:
1780 {
1781 Ice::IntSeq seq(sz);
1782 Ice::Int i = 0;
1783 zval* val;
1784 ZEND_HASH_FOREACH_VAL(arr, val)
1785 {
1786 if(!pi->validate(val, true))
1787 {
1788 throw AbortMarshaling();
1789 }
1790 long l = static_cast<long>(Z_LVAL_P(val));
1791 assert(l >= INT_MIN && l <= INT_MAX);
1792 seq[i++] = static_cast<Ice::Int>(l);
1793 }
1794 ZEND_HASH_FOREACH_END();
1795
1796 os->write(&seq[0], &seq[0] + seq.size());
1797 break;
1798 }
1799 case PrimitiveInfo::KindLong:
1800 {
1801 Ice::LongSeq seq(sz);
1802 Ice::Int i = 0;
1803 zval* val;
1804 ZEND_HASH_FOREACH_VAL(arr, val)
1805 {
1806 if(!pi->validate(val, true))
1807 {
1808 throw AbortMarshaling();
1809 }
1810 //
1811 // The platform's 'long' type may not be 64 bits, so we also accept
1812 // a string argument for this type.
1813 //
1814 assert(Z_TYPE_P(val) == IS_LONG || Z_TYPE_P(val) == IS_STRING);
1815 Ice::Long l;
1816 if(Z_TYPE_P(val) == IS_LONG)
1817 {
1818 l = static_cast<long>(Z_LVAL_P(val));
1819 }
1820 else
1821 {
1822 string sval(Z_STRVAL_P(val), Z_STRLEN_P(val));
1823 IceUtilInternal::stringToInt64(sval, l);
1824 }
1825 seq[i++] = l;
1826 }
1827 ZEND_HASH_FOREACH_END();
1828
1829 os->write(&seq[0], &seq[0] + seq.size());
1830 break;
1831 }
1832 case PrimitiveInfo::KindFloat:
1833 {
1834 Ice::FloatSeq seq(sz);
1835 Ice::Int i = 0;
1836 zval* val;
1837 ZEND_HASH_FOREACH_VAL(arr, val)
1838 {
1839 if(!pi->validate(val, true))
1840 {
1841 throw AbortMarshaling();
1842 }
1843 double d = 0;
1844 if(Z_TYPE_P(val) == IS_DOUBLE)
1845 {
1846 d = Z_DVAL_P(val);
1847 }
1848 else if(Z_TYPE_P(val) == IS_LONG)
1849 {
1850 d = static_cast<double>(Z_LVAL_P(val));
1851 }
1852 else
1853 {
1854 assert(false); // validate() should have caught this.
1855 }
1856 seq[i++] = static_cast<Ice::Float>(d);
1857 }
1858 ZEND_HASH_FOREACH_END();
1859
1860 os->write(&seq[0], &seq[0] + seq.size());
1861 break;
1862 }
1863 case PrimitiveInfo::KindDouble:
1864 {
1865 Ice::DoubleSeq seq(sz);
1866 Ice::Int i = 0;
1867 zval* val;
1868 ZEND_HASH_FOREACH_VAL(arr, val)
1869 {
1870 if(!pi->validate(val, true))
1871 {
1872 throw AbortMarshaling();
1873 }
1874 double d = 0;
1875 if(Z_TYPE_P(val) == IS_DOUBLE)
1876 {
1877 d = Z_DVAL_P(val);
1878 }
1879 else if(Z_TYPE_P(val) == IS_LONG)
1880 {
1881 d = static_cast<double>(Z_LVAL_P(val));
1882 }
1883 else
1884 {
1885 assert(false); // validate() should have caught this.
1886 }
1887 seq[i++] = d;
1888 }
1889 ZEND_HASH_FOREACH_END();
1890
1891 os->write(&seq[0], &seq[0] + seq.size());
1892 break;
1893 }
1894 case PrimitiveInfo::KindString:
1895 {
1896 Ice::StringSeq seq(sz);
1897 Ice::Int i = 0;
1898 zval* val;
1899 ZEND_HASH_FOREACH_VAL(arr, val)
1900 {
1901 if(!pi->validate(val, true))
1902 {
1903 throw AbortMarshaling();
1904 }
1905 string s;
1906 if(Z_TYPE_P(val) == IS_STRING)
1907 {
1908 s = string(Z_STRVAL_P(val), Z_STRLEN_P(val));
1909 }
1910 else
1911 {
1912 assert(Z_TYPE_P(val) == IS_NULL);
1913 }
1914 seq[i++] = s;
1915 }
1916 ZEND_HASH_FOREACH_END();
1917
1918 os->write(seq);
1919 break;
1920 }
1921 }
1922 }
1923
1924 void
unmarshalPrimitiveSequence(const PrimitiveInfoPtr & pi,Ice::InputStream * is,const UnmarshalCallbackPtr & cb,zval * target,void * closure)1925 IcePHP::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, Ice::InputStream* is,
1926 const UnmarshalCallbackPtr& cb, zval* target, void* closure)
1927 {
1928 zval zv;
1929 array_init(&zv);
1930 AutoDestroy destroy(&zv);
1931
1932 switch(pi->kind)
1933 {
1934 case PrimitiveInfo::KindBool:
1935 {
1936 pair<const bool*, const bool*> pr;
1937 IceUtil::ScopedArray<bool> arr;
1938 is->read(pr, arr);
1939 for(const bool* p = pr.first; p != pr.second; ++p)
1940 {
1941 add_next_index_bool(&zv, *p ? 1 : 0);
1942 }
1943 break;
1944 }
1945 case PrimitiveInfo::KindByte:
1946 {
1947 pair<const Ice::Byte*, const Ice::Byte*> pr;
1948 is->read(pr);
1949 for(const Ice::Byte* p = pr.first; p != pr.second; ++p)
1950 {
1951 add_next_index_long(&zv, *p & 0xff);
1952 }
1953 break;
1954 }
1955 case PrimitiveInfo::KindShort:
1956 {
1957 pair<const Ice::Short*, const Ice::Short*> pr;
1958 IceUtil::ScopedArray<Ice::Short> arr;
1959 is->read(pr, arr);
1960 for(const Ice::Short* p = pr.first; p != pr.second; ++p)
1961 {
1962 add_next_index_long(&zv, *p);
1963 }
1964 break;
1965 }
1966 case PrimitiveInfo::KindInt:
1967 {
1968 pair<const Ice::Int*, const Ice::Int*> pr;
1969 IceUtil::ScopedArray<Ice::Int> arr;
1970 is->read(pr, arr);
1971 for(const Ice::Int* p = pr.first; p != pr.second; ++p)
1972 {
1973 add_next_index_long(&zv, *p);
1974 }
1975 break;
1976 }
1977 case PrimitiveInfo::KindLong:
1978 {
1979 pair<const Ice::Long*, const Ice::Long*> pr;
1980 IceUtil::ScopedArray<Ice::Long> arr;
1981 is->read(pr, arr);
1982 Ice::Int i = 0;
1983 for(const Ice::Long* p = pr.first; p != pr.second; ++p, ++i)
1984 {
1985 zval val;
1986 //
1987 // The platform's 'long' type may not be 64 bits, so we store 64-bit
1988 // values as a string.
1989 //
1990 if(sizeof(Ice::Long) > sizeof(long) && (*p < LONG_MIN || *p > LONG_MAX))
1991 {
1992 string str = IceUtilInternal::int64ToString(*p);
1993 ZVAL_STRINGL(&val, STRCAST(str.c_str()), static_cast<int>(str.length()));
1994 }
1995 else
1996 {
1997 ZVAL_LONG(&val, static_cast<long>(*p));
1998 }
1999 add_index_zval(&zv, i, &val);
2000 }
2001 break;
2002 }
2003 case PrimitiveInfo::KindFloat:
2004 {
2005 pair<const Ice::Float*, const Ice::Float*> pr;
2006 IceUtil::ScopedArray<Ice::Float> arr;
2007 is->read(pr, arr);
2008 Ice::Int i = 0;
2009 for(const Ice::Float* p = pr.first; p != pr.second; ++p, ++i)
2010 {
2011 zval val;
2012 ZVAL_DOUBLE(&val, *p);
2013 add_index_zval(&zv, i, &val);
2014 }
2015 break;
2016 }
2017 case PrimitiveInfo::KindDouble:
2018 {
2019 pair<const Ice::Double*, const Ice::Double*> pr;
2020 IceUtil::ScopedArray<Ice::Double> arr;
2021 is->read(pr, arr);
2022 Ice::Int i = 0;
2023 for(const Ice::Double* p = pr.first; p != pr.second; ++p, ++i)
2024 {
2025 zval val;
2026 ZVAL_DOUBLE(&val, *p);
2027 add_index_zval(&zv, i, &val);
2028 }
2029 break;
2030 }
2031 case PrimitiveInfo::KindString:
2032 {
2033 Ice::StringSeq seq;
2034 is->read(seq, true);
2035 Ice::Int i = 0;
2036 for(Ice::StringSeq::iterator p = seq.begin(); p != seq.end(); ++p, ++i)
2037 {
2038 zval val;
2039 ZVAL_STRINGL(&val, STRCAST(p->c_str()), static_cast<int>(p->length()));
2040 add_index_zval(&zv, i, &val);
2041 }
2042 break;
2043 }
2044 }
2045
2046 cb->unmarshaled(&zv, target, closure);
2047 }
2048
2049 //
2050 // DictionaryInfo implementation.
2051 //
DictionaryInfo(const string & ident,zval * k,zval * v)2052 IcePHP::DictionaryInfo::DictionaryInfo(const string& ident, zval* k, zval* v) :
2053 id(ident)
2054 {
2055 const_cast<TypeInfoPtr&>(keyType) = Wrapper<TypeInfoPtr>::value(k);
2056 const_cast<TypeInfoPtr&>(valueType) = Wrapper<TypeInfoPtr>::value(v);
2057
2058 _variableLength = keyType->variableLength() || valueType->variableLength();
2059 _wireSize = keyType->wireSize() + valueType->wireSize();
2060 }
2061
2062 string
getId() const2063 IcePHP::DictionaryInfo::getId() const
2064 {
2065 return id;
2066 }
2067
2068 bool
validate(zval * zv,bool)2069 IcePHP::DictionaryInfo::validate(zval* zv, bool)
2070 {
2071 return Z_TYPE_P(zv) == IS_NULL || Z_TYPE_P(zv) == IS_ARRAY;
2072 }
2073
2074 bool
variableLength() const2075 IcePHP::DictionaryInfo::variableLength() const
2076 {
2077 return true;
2078 }
2079
2080 int
wireSize() const2081 IcePHP::DictionaryInfo::wireSize() const
2082 {
2083 return 1;
2084 }
2085
2086 Ice::OptionalFormat
optionalFormat() const2087 IcePHP::DictionaryInfo::optionalFormat() const
2088 {
2089 return _variableLength ? Ice::OptionalFormatFSize : Ice::OptionalFormatVSize;
2090 }
2091
2092 bool
usesClasses() const2093 IcePHP::DictionaryInfo::usesClasses() const
2094 {
2095 return valueType->usesClasses();
2096 }
2097
2098 void
marshal(zval * zv,Ice::OutputStream * os,ObjectMap * objectMap,bool optional)2099 IcePHP::DictionaryInfo::marshal(zval* zv, Ice::OutputStream* os, ObjectMap* objectMap, bool optional)
2100 {
2101 Ice::Int sz = 0;
2102 HashTable* arr = 0;
2103
2104 if(Z_TYPE_P(zv) != IS_NULL)
2105 {
2106 assert(Z_TYPE_P(zv) == IS_ARRAY); // validate() should have caught this.
2107 arr = Z_ARRVAL_P(zv);
2108 sz = static_cast<Ice::Int>(zend_hash_num_elements(arr));
2109 }
2110
2111 Ice::OutputStream::size_type sizePos = 0;
2112 if(optional)
2113 {
2114 if(_variableLength)
2115 {
2116 sizePos = os->startSize();
2117 }
2118 else
2119 {
2120 os->writeSize(sz == 0 ? 1 : sz * _wireSize + (sz > 254 ? 5 : 1));
2121 }
2122 }
2123
2124 PrimitiveInfoPtr piKey = PrimitiveInfoPtr::dynamicCast(keyType);
2125 EnumInfoPtr enKey = EnumInfoPtr::dynamicCast(keyType);
2126 if(!enKey && (!piKey || piKey->kind == PrimitiveInfo::KindFloat || piKey->kind == PrimitiveInfo::KindDouble))
2127 {
2128 invalidArgument("dictionary type `%s' cannot be marshaled", id.c_str());
2129 throw AbortMarshaling();
2130 }
2131
2132 os->writeSize(sz);
2133
2134 if(sz > 0)
2135 {
2136 zend_long num_key;
2137 zend_string* key;
2138 zval* val;
2139
2140 ZEND_HASH_FOREACH_KEY_VAL(arr, num_key, key, val)
2141 {
2142 //
2143 // Store the key (which can be a long or a string) in a zval so that we can reuse the marshaling logic.
2144 //
2145 zval zkey;
2146 AutoDestroy destroy(&zkey);
2147
2148 if(key)
2149 {
2150 ZVAL_STRINGL(&zkey, key->val, key->len);
2151 }
2152 else
2153 {
2154 ZVAL_LONG(&zkey, num_key);
2155 }
2156
2157 //
2158 // Convert the zval to the required type, if necessary.
2159 //
2160 if(piKey)
2161 {
2162 switch(piKey->kind)
2163 {
2164 case PrimitiveInfo::KindBool:
2165 {
2166 convert_to_boolean(&zkey);
2167 break;
2168 }
2169
2170 case PrimitiveInfo::KindByte:
2171 case PrimitiveInfo::KindShort:
2172 case PrimitiveInfo::KindInt:
2173 case PrimitiveInfo::KindLong:
2174 {
2175 if(key) // HASH_KEY_IS_STRING
2176 {
2177 convert_to_long(&zkey);
2178 }
2179 break;
2180 }
2181
2182 case PrimitiveInfo::KindString:
2183 {
2184 if(!key) // HASH_KEY_IS_LONG
2185 {
2186 convert_to_string(&zkey);
2187 }
2188 break;
2189 }
2190
2191 case PrimitiveInfo::KindFloat:
2192 case PrimitiveInfo::KindDouble:
2193 assert(false);
2194 }
2195 }
2196 else
2197 {
2198 if(key) // HASH_KEY_IS_STRING
2199 {
2200 convert_to_long(&zkey);
2201 }
2202 }
2203
2204 //
2205 // Marshal the key.
2206 //
2207 if(!keyType->validate(&zkey, false))
2208 {
2209 invalidArgument("invalid key in `%s' element", id.c_str());
2210 throw AbortMarshaling();
2211 }
2212 keyType->marshal(&zkey, os, objectMap, false);
2213
2214 //
2215 // Marshal the value.
2216 //
2217 if(!valueType->validate(val, false))
2218 {
2219 invalidArgument("invalid value in `%s' element", id.c_str());
2220 throw AbortMarshaling();
2221 }
2222 valueType->marshal(val, os, objectMap, false);
2223 }
2224 ZEND_HASH_FOREACH_END();
2225 }
2226
2227 if(optional && _variableLength)
2228 {
2229 os->endSize(sizePos);
2230 }
2231 }
2232
2233 void
unmarshal(Ice::InputStream * is,const UnmarshalCallbackPtr & cb,const CommunicatorInfoPtr & comm,zval * target,void * closure,bool optional)2234 IcePHP::DictionaryInfo::unmarshal(Ice::InputStream* is, const UnmarshalCallbackPtr& cb,
2235 const CommunicatorInfoPtr& comm, zval* target, void* closure, bool optional)
2236 {
2237 if(optional)
2238 {
2239 if(_variableLength)
2240 {
2241 is->skip(4);
2242 }
2243 else
2244 {
2245 is->skipSize();
2246 }
2247 }
2248
2249 PrimitiveInfoPtr piKey = PrimitiveInfoPtr::dynamicCast(keyType);
2250 EnumInfoPtr enKey = EnumInfoPtr::dynamicCast(keyType);
2251 if(!enKey && (!piKey || piKey->kind == PrimitiveInfo::KindFloat || piKey->kind == PrimitiveInfo::KindDouble))
2252 {
2253 invalidArgument("dictionary type `%s' cannot be unmarshaled", id.c_str());
2254 throw AbortMarshaling();
2255 }
2256
2257 zval zv;
2258 array_init(&zv);
2259 #ifdef HT_ALLOW_COW_VIOLATION
2260 HT_ALLOW_COW_VIOLATION(Z_ARRVAL(zv)); // Allow circular references.
2261 #endif
2262 AutoDestroy destroy(&zv);
2263
2264 Ice::Int sz = is->readSize();
2265 for(Ice::Int i = 0; i < sz; ++i)
2266 {
2267 //
2268 // A dictionary key cannot be a class (or contain one), so the key must be
2269 // available immediately.
2270 //
2271 KeyCallbackPtr keyCB = new KeyCallback;
2272 keyType->unmarshal(is, keyCB, comm, 0, 0, false);
2273 assert(Z_TYPE(keyCB->key) != IS_UNDEF);
2274
2275 //
2276 // Allocate a callback that holds a reference to the key.
2277 //
2278 ValueCallbackPtr valueCB = new ValueCallback(&keyCB->key);
2279
2280 //
2281 // Pass the key to the callback.
2282 //
2283 valueType->unmarshal(is, valueCB, comm, &zv, 0, false);
2284 }
2285
2286 cb->unmarshaled(&zv, target, closure);
2287 }
2288
2289 void
print(zval * zv,IceUtilInternal::Output & out,PrintObjectHistory * history)2290 IcePHP::DictionaryInfo::print(zval* zv, IceUtilInternal::Output& out, PrintObjectHistory* history)
2291 {
2292 if(!validate(zv, false))
2293 {
2294 out << "<invalid value - expected " << id << ">";
2295 return;
2296 }
2297
2298 if(Z_TYPE_P(zv) == IS_NULL)
2299 {
2300 out << "{}";
2301 }
2302 else
2303 {
2304 HashTable* arr = Z_ARRVAL_P(zv);
2305 zval* val;
2306 zend_long num_key;
2307 zend_string* key;
2308 bool first = true;
2309
2310 out.sb();
2311
2312 ZEND_HASH_FOREACH_KEY_VAL(arr, num_key, key, val)
2313 {
2314 if(first)
2315 {
2316 first = false;
2317 }
2318 else
2319 {
2320 out << nl;
2321 }
2322 out << nl << "key = ";
2323
2324 if(key) // HASH_KEY_IS_STRING
2325 {
2326 out << key->val;
2327 }
2328 else // HASH_KEY_IS_LONG
2329 {
2330 out << num_key;
2331 }
2332 out << nl << "value = ";
2333 valueType->print(val, out, history);
2334 }
2335 ZEND_HASH_FOREACH_END();
2336
2337 out.eb();
2338 }
2339 }
2340
KeyCallback()2341 IcePHP::DictionaryInfo::KeyCallback::KeyCallback()
2342 {
2343 ZVAL_UNDEF(&key);
2344 }
2345
~KeyCallback()2346 IcePHP::DictionaryInfo::KeyCallback::~KeyCallback()
2347 {
2348 zval_ptr_dtor(&key);
2349 }
2350
2351 void
unmarshaled(zval * zv,zval *,void *)2352 IcePHP::DictionaryInfo::KeyCallback::unmarshaled(zval* zv, zval*, void*)
2353 {
2354 zval_ptr_dtor(&key);
2355 ZVAL_COPY(&key, zv);
2356 }
2357
ValueCallback(zval * k)2358 IcePHP::DictionaryInfo::ValueCallback::ValueCallback(zval* k)
2359 {
2360 ZVAL_COPY_VALUE(&key, k);
2361 }
2362
~ValueCallback()2363 IcePHP::DictionaryInfo::ValueCallback::~ValueCallback()
2364 {
2365 }
2366
2367 void
unmarshaled(zval * zv,zval * target,void *)2368 IcePHP::DictionaryInfo::ValueCallback::unmarshaled(zval* zv, zval* target, void*)
2369 {
2370 assert(Z_TYPE_P(target) == IS_ARRAY);
2371
2372 switch(Z_TYPE(key))
2373 {
2374 case IS_LONG:
2375 add_index_zval(target, Z_LVAL(key), zv);
2376 break;
2377 case IS_TRUE:
2378 add_index_zval(target, 1, zv);
2379 break;
2380 case IS_FALSE:
2381 add_index_zval(target, 0, zv);
2382 break;
2383 case IS_STRING:
2384 add_assoc_zval_ex(target, Z_STRVAL(key), Z_STRLEN(key), zv);
2385 break;
2386 default:
2387 assert(false);
2388 return;
2389 }
2390
2391 Z_TRY_ADDREF_P(zv);
2392 }
2393
2394 void
destroy()2395 IcePHP::DictionaryInfo::destroy()
2396 {
2397 if(keyType)
2398 {
2399 keyType->destroy();
2400 keyType = 0;
2401 }
2402 if(valueType)
2403 {
2404 valueType->destroy();
2405 valueType = 0;
2406 }
2407 }
2408
2409 //
2410 // ClassInfo implementation.
2411 //
ClassInfo(const string & ident)2412 IcePHP::ClassInfo::ClassInfo(const string& ident) :
2413 id(ident), compactId(-1), preserve(false), interface(false), zce(0), defined(false)
2414 {
2415 }
2416
2417 void
define(const string & n,Ice::Int compact,bool pres,bool intf,zval * b,zval * m)2418 IcePHP::ClassInfo::define(const string& n, Ice::Int compact, bool pres, bool intf, zval* b, zval* m)
2419 {
2420 const_cast<string&>(name) = n;
2421 const_cast<Ice::Int&>(compactId) = static_cast<Ice::Int>(compact);
2422 const_cast<bool&>(preserve) = pres;
2423 const_cast<bool&>(interface) = intf;
2424
2425 if(b)
2426 {
2427 TypeInfoPtr p = Wrapper<TypeInfoPtr>::value(b);
2428 const_cast<ClassInfoPtr&>(base) = ClassInfoPtr::dynamicCast(p);
2429 assert(base);
2430 }
2431
2432 if(m)
2433 {
2434 convertDataMembers(m, const_cast<DataMemberList&>(members), const_cast<DataMemberList&>(optionalMembers),
2435 true);
2436 }
2437
2438 const_cast<bool&>(defined) = true;
2439 #ifdef ICEPHP_USE_NAMESPACES
2440 const string valueClass = "Ice\\Value";
2441 #else
2442 const string valueClass = "Ice_Value";
2443 #endif
2444 const_cast<zend_class_entry*&>(zce) = nameToClass(interface ? valueClass : name);
2445 assert(zce || id == "::Ice::LocalObject" || interface); // LocalObject and interfaces does not have a native PHP equivalent.
2446 }
2447
2448 string
getId() const2449 IcePHP::ClassInfo::getId() const
2450 {
2451 return id;
2452 }
2453
2454 bool
validate(zval * val,bool)2455 IcePHP::ClassInfo::validate(zval* val, bool)
2456 {
2457 if(Z_TYPE_P(val) == IS_OBJECT)
2458 {
2459 return checkClass(Z_OBJCE_P(val), const_cast<zend_class_entry*>(zce));
2460 }
2461 return Z_TYPE_P(val) == IS_NULL;
2462 }
2463
2464 bool
variableLength() const2465 IcePHP::ClassInfo::variableLength() const
2466 {
2467 return true;
2468 }
2469
2470 int
wireSize() const2471 IcePHP::ClassInfo::wireSize() const
2472 {
2473 return 1;
2474 }
2475
2476 Ice::OptionalFormat
optionalFormat() const2477 IcePHP::ClassInfo::optionalFormat() const
2478 {
2479 return Ice::OptionalFormatClass;
2480 }
2481
2482 bool
usesClasses() const2483 IcePHP::ClassInfo::usesClasses() const
2484 {
2485 return true;
2486 }
2487
2488 void
marshal(zval * zv,Ice::OutputStream * os,ObjectMap * objectMap,bool)2489 IcePHP::ClassInfo::marshal(zval* zv, Ice::OutputStream* os, ObjectMap* objectMap, bool)
2490 {
2491 if(!defined)
2492 {
2493 runtimeError("class or interface %s is declared but not defined", id.c_str());
2494 throw AbortMarshaling();
2495 }
2496
2497 if(Z_TYPE_P(zv) == IS_NULL)
2498 {
2499 Ice::ObjectPtr nil;
2500 os->write(nil);
2501 return;
2502 }
2503
2504 assert(Z_TYPE_P(zv) == IS_OBJECT); // validate() should have caught this.
2505 assert(checkClass(Z_OBJCE_P(zv), const_cast<zend_class_entry*>(zce))); // validate() should have caught this.
2506
2507 //
2508 // Ice::ObjectWriter is a subclass of Ice::Object that wraps a PHP object for marshaling.
2509 // It is possible that this PHP object has already been marshaled, therefore we first must
2510 // check the object map to see if this object is present. If so, we use the existing ObjectWriter,
2511 // otherwise we create a new one. The key of the map is the object's handle.
2512 //
2513 Ice::ObjectPtr writer;
2514 assert(objectMap);
2515 ObjectMap::iterator q = objectMap->find(Z_OBJ_HANDLE_P(zv));
2516 if(q == objectMap->end())
2517 {
2518 writer = new ObjectWriter(zv, objectMap, this);
2519 objectMap->insert(ObjectMap::value_type(Z_OBJ_HANDLE_P(zv), writer));
2520 }
2521 else
2522 {
2523 writer = q->second;
2524 }
2525
2526 //
2527 // Give the writer to the stream. The stream will eventually call write() on it.
2528 //
2529 os->write(writer);
2530 }
2531
2532 namespace
2533 {
2534
2535 void
patchObject(void * addr,const Ice::ObjectPtr & v)2536 patchObject(void* addr, const Ice::ObjectPtr& v)
2537 {
2538 ReadObjectCallback* cb = static_cast<ReadObjectCallback*>(addr);
2539 assert(cb);
2540 cb->invoke(v);
2541 }
2542
2543 }
2544
2545 void
unmarshal(Ice::InputStream * is,const UnmarshalCallbackPtr & cb,const CommunicatorInfoPtr & comm,zval * target,void * closure,bool)2546 IcePHP::ClassInfo::unmarshal(Ice::InputStream* is, const UnmarshalCallbackPtr& cb,
2547 const CommunicatorInfoPtr& comm, zval* target, void* closure, bool)
2548 {
2549 if(!defined)
2550 {
2551 runtimeError("class or interface %s is declared but not defined", id.c_str());
2552 throw AbortMarshaling();
2553 }
2554
2555 //
2556 // This callback is notified when the Slice value is actually read. The StreamUtil object
2557 // attached to the stream keeps a reference to the callback object to ensure it lives
2558 // long enough.
2559 //
2560 ReadObjectCallbackPtr rocb = new ReadObjectCallback(this, cb, target, closure);
2561 StreamUtil* util = reinterpret_cast<StreamUtil*>(is->getClosure());
2562 assert(util);
2563 util->add(rocb);
2564 is->read(patchObject, rocb.get());
2565 }
2566
2567 void
print(zval * zv,IceUtilInternal::Output & out,PrintObjectHistory * history)2568 IcePHP::ClassInfo::print(zval* zv, IceUtilInternal::Output& out, PrintObjectHistory* history)
2569 {
2570 if(!validate(zv, false))
2571 {
2572 out << "<invalid value - expected " << id << ">";
2573 return;
2574 }
2575
2576 if(Z_TYPE_P(zv) == IS_NULL)
2577 {
2578 out << "<nil>";
2579 }
2580 else
2581 {
2582 map<unsigned int, int>::iterator q = history->objects.find(Z_OBJ_HANDLE_P(zv));
2583 if(q != history->objects.end())
2584 {
2585 out << "<object #" << q->second << ">";
2586 }
2587 else
2588 {
2589 out << "object #" << history->index << " (" << id << ')';
2590 history->objects.insert(map<unsigned int, int>::value_type(Z_OBJ_HANDLE_P(zv), history->index));
2591 ++history->index;
2592 out.sb();
2593 printMembers(zv, out, history);
2594 out.eb();
2595 }
2596 }
2597 }
2598
2599 void
destroy()2600 IcePHP::ClassInfo::destroy()
2601 {
2602 const_cast<ClassInfoPtr&>(base) = 0;
2603 if(!members.empty())
2604 {
2605 DataMemberList ml = members;
2606 const_cast<DataMemberList&>(members).clear();
2607 for(DataMemberList::iterator p = ml.begin(); p != ml.end(); ++p)
2608 {
2609 (*p)->type->destroy();
2610 }
2611 }
2612 }
2613
2614 void
printMembers(zval * zv,IceUtilInternal::Output & out,PrintObjectHistory * history)2615 IcePHP::ClassInfo::printMembers(zval* zv, IceUtilInternal::Output& out, PrintObjectHistory* history)
2616 {
2617 if(base)
2618 {
2619 base->printMembers(zv, out, history);
2620 }
2621
2622 DataMemberList::const_iterator q;
2623
2624 for(q = members.begin(); q != members.end(); ++q)
2625 {
2626 DataMemberPtr member = *q;
2627
2628 out << nl << member->name << " = ";
2629 zval* val = zend_hash_str_find(Z_OBJPROP_P(zv), STRCAST(member->name.c_str()), member->name.size());
2630 assert(Z_TYPE_P(val) == IS_INDIRECT);
2631 val = Z_INDIRECT_P(val);
2632 if(val)
2633 {
2634 member->type->print(val, out, history);
2635 }
2636 else
2637 {
2638 out << "<not defined>";
2639 }
2640 }
2641
2642 for(q = optionalMembers.begin(); q != optionalMembers.end(); ++q)
2643 {
2644 DataMemberPtr member = *q;
2645
2646 out << nl << member->name << " = ";
2647 zval* val = zend_hash_str_find(Z_OBJPROP_P(zv), STRCAST(member->name.c_str()), member->name.size());
2648 assert(Z_TYPE_P(val) == IS_INDIRECT);
2649 val = Z_INDIRECT_P(val);
2650 if(val)
2651 {
2652 if(isUnset(val))
2653 {
2654 out << "<unset>";
2655 }
2656 else
2657 {
2658 member->type->print(val, out, history);
2659 }
2660 }
2661 else
2662 {
2663 out << "<not defined>";
2664 }
2665 }
2666 }
2667
2668 bool
isA(const string & typeId) const2669 IcePHP::ClassInfo::isA(const string& typeId) const
2670 {
2671 if(id == typeId)
2672 {
2673 return true;
2674 }
2675
2676 return base && base->isA(typeId);
2677 }
2678
2679 //
2680 // ProxyInfo implementation.
2681 //
ProxyInfo(const string & ident)2682 IcePHP::ProxyInfo::ProxyInfo(const string& ident) :
2683 id(ident), defined(false)
2684 {
2685 }
2686
2687 void
define(zval * b,zval * i)2688 IcePHP::ProxyInfo::define(zval* b, zval* i)
2689 {
2690 if(b)
2691 {
2692 TypeInfoPtr p = Wrapper<TypeInfoPtr>::value(b);
2693 const_cast<ProxyInfoPtr&>(base) = ProxyInfoPtr::dynamicCast(p);
2694 assert(base);
2695 }
2696
2697 if(i)
2698 {
2699 HashTable* interfacesArray = Z_ARRVAL_P(i);
2700 zval* interfaceType;
2701
2702 ZEND_HASH_FOREACH_VAL(interfacesArray, interfaceType)
2703 {
2704 TypeInfoPtr t = Wrapper<TypeInfoPtr>::value(interfaceType);
2705 ProxyInfoPtr c = ProxyInfoPtr::dynamicCast(t);
2706 assert(c);
2707 const_cast<ProxyInfoList&>(interfaces).push_back(c);
2708 }
2709 ZEND_HASH_FOREACH_END();
2710 }
2711
2712 const_cast<bool&>(defined) = true;
2713 }
2714
2715 string
getId() const2716 IcePHP::ProxyInfo::getId() const
2717 {
2718 return id;
2719 }
2720
2721 bool
validate(zval * zv,bool throwException)2722 IcePHP::ProxyInfo::validate(zval* zv, bool throwException)
2723 {
2724 if(Z_TYPE_P(zv) != IS_NULL)
2725 {
2726 if(Z_TYPE_P(zv) != IS_OBJECT || (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) != proxyClassEntry))
2727 {
2728 if(throwException)
2729 {
2730 string s = zendTypeToString(Z_TYPE_P(zv));
2731 invalidArgument("expected proxy value or null but received %s", s.c_str());
2732 }
2733 return false;
2734 }
2735 }
2736
2737 return true;
2738 }
2739
2740 bool
variableLength() const2741 IcePHP::ProxyInfo::variableLength() const
2742 {
2743 return true;
2744 }
2745
2746 int
wireSize() const2747 IcePHP::ProxyInfo::wireSize() const
2748 {
2749 return 1;
2750 }
2751
2752 Ice::OptionalFormat
optionalFormat() const2753 IcePHP::ProxyInfo::optionalFormat() const
2754 {
2755 return Ice::OptionalFormatFSize;
2756 }
2757
2758 void
marshal(zval * zv,Ice::OutputStream * os,ObjectMap *,bool optional)2759 IcePHP::ProxyInfo::marshal(zval* zv, Ice::OutputStream* os, ObjectMap*, bool optional)
2760 {
2761 Ice::OutputStream::size_type sizePos = 0;
2762 if(optional)
2763 {
2764 sizePos = os->startSize();
2765 }
2766
2767 if(Z_TYPE_P(zv) == IS_NULL)
2768 {
2769 os->write(Ice::ObjectPrx());
2770 }
2771 else
2772 {
2773 assert(Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == proxyClassEntry); // validate() should have caught this.
2774 Ice::ObjectPrx proxy;
2775 ProxyInfoPtr info;
2776 if(!fetchProxy(zv, proxy, info))
2777 {
2778 throw AbortMarshaling();
2779 }
2780 if(!info->isA(id))
2781 {
2782 invalidArgument("proxy is not narrowed to %s", id.c_str());
2783 throw AbortMarshaling();
2784 }
2785 os->write(proxy);
2786 }
2787
2788 if(optional)
2789 {
2790 os->endSize(sizePos);
2791 }
2792 }
2793
2794 void
unmarshal(Ice::InputStream * is,const UnmarshalCallbackPtr & cb,const CommunicatorInfoPtr & comm,zval * target,void * closure,bool optional)2795 IcePHP::ProxyInfo::unmarshal(Ice::InputStream* is, const UnmarshalCallbackPtr& cb,
2796 const CommunicatorInfoPtr& comm, zval* target, void* closure, bool optional)
2797 {
2798 zval zv;
2799 AutoDestroy destroy(&zv);
2800
2801 if(optional)
2802 {
2803 is->skip(4);
2804 }
2805
2806 Ice::ObjectPrx proxy;
2807 is->read(proxy);
2808
2809 if(!proxy)
2810 {
2811 ZVAL_NULL(&zv);
2812 cb->unmarshaled(&zv, target, closure);
2813 return;
2814 }
2815
2816 if(!defined)
2817 {
2818 runtimeError("proxy %s is declared but not defined" TSRMLS_CC, id.c_str());
2819 throw AbortMarshaling();
2820 }
2821
2822 if(!createProxy(&zv, proxy, this, comm))
2823 {
2824 throw AbortMarshaling();
2825 }
2826 cb->unmarshaled(&zv, target, closure);
2827 }
2828
2829 void
print(zval * zv,IceUtilInternal::Output & out,PrintObjectHistory *)2830 IcePHP::ProxyInfo::print(zval* zv, IceUtilInternal::Output& out, PrintObjectHistory*)
2831 {
2832 if(!validate(zv, false))
2833 {
2834 out << "<invalid value - expected " << id << ">";
2835 return;
2836 }
2837
2838 if(Z_TYPE_P(zv) == IS_NULL)
2839 {
2840 out << "<nil>";
2841 }
2842 else
2843 {
2844 Ice::ObjectPrx proxy;
2845 ProxyInfoPtr info;
2846 if(!fetchProxy(zv, proxy, info))
2847 {
2848 return;
2849 }
2850 out << proxy->ice_toString();
2851 }
2852 }
2853
2854 void
destroy()2855 IcePHP::ProxyInfo::destroy()
2856 {
2857 const_cast<ProxyInfoPtr&>(base) = 0;
2858 const_cast<ProxyInfoList&>(interfaces).clear();
2859 }
2860
2861 bool
isA(const string & typeId) const2862 IcePHP::ProxyInfo::isA(const string& typeId) const
2863 {
2864 if(id == typeId)
2865 {
2866 return true;
2867 }
2868
2869 if(base && base->isA(typeId))
2870 {
2871 return true;
2872 }
2873
2874 for(ProxyInfoList::const_iterator p = interfaces.begin(); p != interfaces.end(); ++p)
2875 {
2876 if((*p)->isA(typeId))
2877 {
2878 return true;
2879 }
2880 }
2881
2882 return false;
2883 }
2884
2885 void
addOperation(const string & name,const OperationPtr & op)2886 IcePHP::ProxyInfo::addOperation(const string& name, const OperationPtr& op)
2887 {
2888 operations.insert(OperationMap::value_type(Slice::PHP::fixIdent(name), op));
2889 }
2890
2891 IcePHP::OperationPtr
getOperation(const string & name) const2892 IcePHP::ProxyInfo::getOperation(const string& name) const
2893 {
2894 OperationPtr op;
2895 OperationMap::const_iterator p = operations.find(name);
2896 if(p != operations.end())
2897 {
2898 op = p->second;
2899 }
2900 if(!op && base)
2901 {
2902 op = base->getOperation(name);
2903 }
2904 if(!op && !interfaces.empty())
2905 {
2906 for(ProxyInfoList::const_iterator q = interfaces.begin(); q != interfaces.end() && !op; ++q)
2907 {
2908 op = (*q)->getOperation(name);
2909 }
2910 }
2911 return op;
2912 }
2913
2914 //
2915 // ObjectWriter implementation.
2916 //
ObjectWriter(zval * object,ObjectMap * objectMap,const ClassInfoPtr & formal)2917 IcePHP::ObjectWriter::ObjectWriter(zval* object, ObjectMap* objectMap, const ClassInfoPtr& formal) :
2918 _map(objectMap), _formal(formal)
2919 {
2920 // Copy zval and increase ref count
2921 ZVAL_COPY(&_object, object);
2922 if(!_formal || !_formal->interface)
2923 {
2924 //
2925 // For non interface types we need to determine the most-derived Slice type supported by
2926 // this object. This is typically a Slice class, but it can also be an interface.
2927 //
2928 // The caller may have provided a ClassInfo representing the formal type, in
2929 // which case we ensure that the actual type is compatible with the formal type.
2930 //
2931 _info = getClassInfoByClass(Z_OBJCE_P(object), formal ? const_cast<zend_class_entry*>(formal->zce) : 0);
2932 assert(_info);
2933 }
2934 }
2935
~ObjectWriter()2936 IcePHP::ObjectWriter::~ObjectWriter()
2937 {
2938 zval_ptr_dtor(&_object);
2939 }
2940
2941 void
ice_preMarshal()2942 IcePHP::ObjectWriter::ice_preMarshal()
2943 {
2944 string name = "ice_premarshal"; // Must be lowercase.
2945 if(zend_hash_str_exists(&Z_OBJCE_P(&_object)->function_table, STRCAST(name.c_str()), static_cast<uint>(name.size())))
2946 {
2947 if(!invokeMethod(&_object, name))
2948 {
2949 throw AbortMarshaling();
2950 }
2951 }
2952 }
2953
2954 void
_iceWrite(Ice::OutputStream * os) const2955 IcePHP::ObjectWriter::_iceWrite(Ice::OutputStream* os) const
2956 {
2957 Ice::SlicedDataPtr slicedData;
2958
2959 if(_info && _info->preserve)
2960 {
2961 //
2962 // Retrieve the SlicedData object that we stored as a hidden member of the PHP object.
2963 //
2964 slicedData = StreamUtil::getSlicedDataMember(const_cast<zval*>(&_object), const_cast<ObjectMap*>(_map));
2965 }
2966
2967 os->startValue(slicedData);
2968
2969 if(_formal && _formal->interface)
2970 {
2971 //
2972 // For an interface by value we just marshal the Ice type id
2973 // of the object in its own slice.
2974 //
2975 zval ret;
2976 ZVAL_UNDEF(&ret);
2977
2978 zend_try
2979 {
2980 assert(Z_TYPE(_object) == IS_OBJECT);
2981 zend_call_method(const_cast<zval*>(&_object), 0, 0, const_cast<char*>("ice_id"), sizeof("ice_id") - 1, &ret, 0, 0, 0);
2982 }
2983 zend_catch
2984 {
2985 // ret;
2986 }
2987 zend_end_try();
2988
2989 //
2990 // Bail out if an exception has already been thrown.
2991 //
2992 if(Z_ISUNDEF(ret) || EG(exception))
2993 {
2994 throw AbortMarshaling();
2995 }
2996
2997 AutoDestroy destroy(&ret);
2998
2999 if(Z_TYPE(ret) != IS_STRING)
3000 {
3001 throw AbortMarshaling();
3002 }
3003
3004 string id(Z_STRVAL(ret), Z_STRLEN(ret));
3005 os->startSlice(id, -1, true);
3006 os->endSlice();
3007 }
3008 else
3009 {
3010 if(_info->id != "::Ice::UnknownSlicedValue")
3011 {
3012 ClassInfoPtr info = _info;
3013 while(info && info->id != Ice::Object::ice_staticId())
3014 {
3015 assert(info->base); // All classes have the Ice::Object base type.
3016 const bool lastSlice = info->base->id == Ice::Object::ice_staticId();
3017 os->startSlice(info->id, info->compactId, lastSlice);
3018
3019 writeMembers(os, info->members);
3020 writeMembers(os, info->optionalMembers); // The optional members have already been sorted by tag.
3021
3022 os->endSlice();
3023
3024 info = info->base;
3025 }
3026 }
3027 }
3028 os->endValue();
3029 }
3030
3031 void
_iceRead(Ice::InputStream *)3032 IcePHP::ObjectWriter::_iceRead(Ice::InputStream*)
3033 {
3034 assert(false);
3035 }
3036
3037 void
writeMembers(Ice::OutputStream * os,const DataMemberList & members) const3038 IcePHP::ObjectWriter::writeMembers(Ice::OutputStream* os, const DataMemberList& members) const
3039 {
3040 for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
3041 {
3042 DataMemberPtr member = *q;
3043 zval* val = zend_hash_str_find(Z_OBJPROP_P(const_cast<zval*>(&_object)),
3044 STRCAST(member->name.c_str()), static_cast<int>(member->name.size()));
3045
3046 if(!val)
3047 {
3048 runtimeError("member `%s' of %s is not defined", member->name.c_str(), _info->id.c_str());
3049 throw AbortMarshaling();
3050 }
3051
3052 assert(Z_TYPE_P(val) == IS_INDIRECT);
3053 val = Z_INDIRECT_P(val);
3054
3055 if(Z_TYPE_P(val) == IS_REFERENCE)
3056 {
3057 val = Z_REFVAL_P(val);
3058 }
3059
3060 if(member->optional && (isUnset(val) || !os->writeOptional(member->tag, member->type->optionalFormat())))
3061 {
3062 continue;
3063 }
3064
3065 if(!member->type->validate(val, false))
3066 {
3067 invalidArgument("invalid value for %s member `%s'", _info->id.c_str(), member->name.c_str());
3068 throw AbortMarshaling();
3069 }
3070
3071 member->type->marshal(val, os, _map, member->optional);
3072 }
3073 }
3074
3075 //
3076 // ObjectReader implementation.
3077 //
ObjectReader(zval * object,const ClassInfoPtr & info,const CommunicatorInfoPtr & comm)3078 IcePHP::ObjectReader::ObjectReader(zval* object, const ClassInfoPtr& info, const CommunicatorInfoPtr& comm) :
3079 _info(info), _communicator(comm)
3080 {
3081 assert(Z_TYPE_P(object) == IS_OBJECT);
3082 ZVAL_DUP(&_object, object);
3083 }
3084
~ObjectReader()3085 IcePHP::ObjectReader::~ObjectReader()
3086 {
3087 zval_ptr_dtor(&_object);
3088 }
3089
3090 void
ice_postUnmarshal()3091 IcePHP::ObjectReader::ice_postUnmarshal()
3092 {
3093 string name = "ice_postunmarshal"; // Must be lowercase.
3094 if(zend_hash_str_exists(&Z_OBJCE(_object)->function_table,
3095 STRCAST(name.c_str()), static_cast<int>(name.size())))
3096 {
3097 if(!invokeMethod(&_object, name))
3098 {
3099 throw AbortMarshaling();
3100 }
3101 }
3102 }
3103
3104 void
_iceWrite(Ice::OutputStream *) const3105 IcePHP::ObjectReader::_iceWrite(Ice::OutputStream*) const
3106 {
3107 assert(false);
3108 }
3109
3110 void
_iceRead(Ice::InputStream * is)3111 IcePHP::ObjectReader::_iceRead(Ice::InputStream* is)
3112 {
3113 is->startValue();
3114 const bool unknown = _info->id == "::Ice::UnknownSlicedValue";
3115
3116 //
3117 // Unmarshal the slices of a user-defined class.
3118 //
3119 if(!unknown)
3120 {
3121 ClassInfoPtr info = _info;
3122
3123 while(info && info->id != Ice::Object::ice_staticId())
3124 {
3125 is->startSlice();
3126
3127 DataMemberList::const_iterator p;
3128
3129 for(p = info->members.begin(); p != info->members.end(); ++p)
3130 {
3131 DataMemberPtr member = *p;
3132 member->type->unmarshal(is, member, _communicator, &_object, 0, false);
3133 }
3134
3135 //
3136 // The optional members have already been sorted by tag.
3137 //
3138 for(p = info->optionalMembers.begin(); p != info->optionalMembers.end(); ++p)
3139 {
3140 DataMemberPtr member = *p;
3141 if(is->readOptional(member->tag, member->type->optionalFormat()))
3142 {
3143 member->type->unmarshal(is, member, _communicator, &_object, 0, true);
3144 }
3145 else
3146 {
3147 zval zv;
3148 AutoDestroy destroy(&zv);
3149 assignUnset(&zv);
3150 member->setMember(&_object, &zv);
3151 }
3152 }
3153
3154 is->endSlice();
3155
3156 info = info->base;
3157 }
3158 }
3159
3160 _slicedData = is->endValue(_info->preserve);
3161
3162 if(_slicedData)
3163 {
3164 StreamUtil* util = reinterpret_cast<StreamUtil*>(is->getClosure());
3165 assert(util);
3166 util->add(this);
3167
3168 //
3169 // Define the "unknownTypeId" member for an instance of UnknownSlicedObject.
3170 //
3171 if(unknown)
3172 {
3173 assert(!_slicedData->slices.empty());
3174
3175 const string typeId = _slicedData->slices[0]->typeId;
3176 zval zv;
3177 AutoDestroy typeIdDestroyer(&zv);
3178 ZVAL_STRINGL(&zv, STRCAST(typeId.c_str()), static_cast<int>(typeId.size()));
3179 add_property_zval(&_object, STRCAST("unknownTypeId"), &zv);
3180 }
3181 }
3182 }
3183
3184 ClassInfoPtr
getInfo() const3185 IcePHP::ObjectReader::getInfo() const
3186 {
3187 return _info;
3188 }
3189
3190 zval*
getObject() const3191 IcePHP::ObjectReader::getObject() const
3192 {
3193 return const_cast<zval*>(&_object);
3194 }
3195
3196 Ice::SlicedDataPtr
getSlicedData() const3197 IcePHP::ObjectReader::getSlicedData() const
3198 {
3199 return _slicedData;
3200 }
3201
3202 //
3203 // ReadObjectCallback implementation.
3204 //
ReadObjectCallback(const ClassInfoPtr & info,const UnmarshalCallbackPtr & cb,zval * target,void * closure)3205 IcePHP::ReadObjectCallback::ReadObjectCallback(const ClassInfoPtr& info, const UnmarshalCallbackPtr& cb,
3206 zval* target, void* closure) :
3207 _info(info), _cb(cb), _closure(closure)
3208 {
3209 ZVAL_NULL(&_target);
3210
3211 if(target)
3212 {
3213 assert(Z_REFCOUNTED_P(target));
3214 ZVAL_COPY(&_target, target);
3215 }
3216 }
3217
~ReadObjectCallback()3218 IcePHP::ReadObjectCallback::~ReadObjectCallback()
3219 {
3220 zval_ptr_dtor(&_target);
3221 }
3222
3223 void
invoke(const Ice::ObjectPtr & p)3224 IcePHP::ReadObjectCallback::invoke(const Ice::ObjectPtr& p)
3225 {
3226 if(p)
3227 {
3228 ObjectReaderPtr reader = ObjectReaderPtr::dynamicCast(p);
3229 assert(reader);
3230
3231 //
3232 // Verify that the unmarshaled object is compatible with the formal type.
3233 //
3234 zval* obj = reader->getObject();
3235 if(!_info->interface && !reader->getInfo()->isA(_info->id))
3236 {
3237 Ice::UnexpectedObjectException ex(__FILE__, __LINE__);
3238 ex.reason = "unmarshaled object is not an instance of " + _info->id;
3239 ex.type = reader->getInfo()->id;
3240 ex.expectedType = _info->id;
3241 throw ex;
3242 }
3243 _cb->unmarshaled(obj, &_target, _closure);
3244 }
3245 else
3246 {
3247 zval zv;
3248 AutoDestroy destroy(&zv);
3249 ZVAL_NULL(&zv);
3250 _cb->unmarshaled(&zv, &_target, _closure);
3251 }
3252 }
3253
3254 //
3255 // ExceptionInfo implementation.
3256 //
3257 zval*
unmarshal(Ice::InputStream * is,const CommunicatorInfoPtr & comm)3258 IcePHP::ExceptionInfo::unmarshal(Ice::InputStream* is, const CommunicatorInfoPtr& comm)
3259 {
3260 zval* zv = static_cast<zval*>(emalloc(sizeof(zval)));
3261
3262 if(object_init_ex(zv, zce) != SUCCESS)
3263 {
3264 runtimeError("unable to initialize object of type %s", zce->name->val);
3265 throw AbortMarshaling();
3266 }
3267
3268 //
3269 // NOTE: The type id for the first slice has already been read.
3270 //
3271 ExceptionInfoPtr info = this;
3272 while(info)
3273 {
3274 is->startSlice();
3275
3276 DataMemberList::iterator q;
3277
3278 for(q = info->members.begin(); q != info->members.end(); ++q)
3279 {
3280 DataMemberPtr member = *q;
3281 member->type->unmarshal(is, member, comm, zv, 0, false);
3282 }
3283
3284 //
3285 // The optional members have already been sorted by tag.
3286 //
3287 for(q = info->optionalMembers.begin(); q != info->optionalMembers.end(); ++q)
3288 {
3289 DataMemberPtr member = *q;
3290 if(is->readOptional(member->tag, member->type->optionalFormat()))
3291 {
3292 member->type->unmarshal(is, member, comm, zv, 0, true);
3293 }
3294 else
3295 {
3296 zval un;
3297 AutoDestroy destroy(&un);
3298 assignUnset(&un);
3299 member->setMember(zv, &un);
3300 }
3301 }
3302
3303 is->endSlice();
3304
3305 info = info->base;
3306 }
3307
3308 return zv;
3309 }
3310
3311 void
print(zval * zv,IceUtilInternal::Output & out)3312 IcePHP::ExceptionInfo::print(zval* zv, IceUtilInternal::Output& out)
3313 {
3314 out << "exception " << id;
3315 out.sb();
3316
3317 if(Z_TYPE_P(zv) != IS_OBJECT)
3318 {
3319 string s = zendTypeToString(Z_TYPE_P(zv));
3320 out << nl << "expected exception value of type " << zce->name->val << " but received " << s;
3321 out.eb();
3322 return;
3323 }
3324
3325 //
3326 // Compare class entries.
3327 //
3328 zend_class_entry* ce = Z_OBJCE_P(zv);
3329 if(ce != zce)
3330 {
3331 out << nl << "expected exception value of type " << zce->name->val << " but received " << ce->name->val;
3332 out.eb();
3333 return;
3334 }
3335
3336 PrintObjectHistory history;
3337 history.index = 0;
3338
3339 printMembers(zv, out, &history);
3340 out.eb();
3341 }
3342
3343 void
printMembers(zval * zv,IceUtilInternal::Output & out,PrintObjectHistory * history)3344 IcePHP::ExceptionInfo::printMembers(zval* zv, IceUtilInternal::Output& out, PrintObjectHistory* history)
3345 {
3346 if(base)
3347 {
3348 base->printMembers(zv, out, history);
3349 }
3350
3351 DataMemberList::iterator q;
3352
3353 for(q = members.begin(); q != members.end(); ++q)
3354 {
3355 DataMemberPtr member = *q;
3356
3357 out << nl << member->name << " = ";
3358 zval* val = zend_hash_str_find(Z_OBJPROP_P(zv),
3359 STRCAST(member->name.c_str()),
3360 static_cast<int>(member->name.size()));
3361
3362 assert(Z_TYPE_P(val) == IS_INDIRECT);
3363 val = Z_INDIRECT_P(val);
3364
3365 if(val)
3366 {
3367 member->type->print(val, out, history);
3368 }
3369 else
3370 {
3371 out << "<not defined>";
3372 }
3373 }
3374
3375 for(q = optionalMembers.begin(); q != optionalMembers.end(); ++q)
3376 {
3377 DataMemberPtr member = *q;
3378
3379 out << nl << member->name << " = ";
3380 zval* val = zend_hash_str_find(Z_OBJPROP_P(zv),
3381 STRCAST(member->name.c_str()),
3382 static_cast<int>(member->name.size()));
3383
3384 assert(Z_TYPE_P(val) == IS_INDIRECT);
3385 val = Z_INDIRECT_P(val);
3386
3387 if(val)
3388 {
3389 if(isUnset(val))
3390 {
3391 out << "<unset>";
3392 }
3393 else
3394 {
3395 member->type->print(val, out, history);
3396 }
3397 }
3398 else
3399 {
3400 out << "<not defined>";
3401 }
3402 }
3403 }
3404
3405 bool
isA(const string & typeId) const3406 IcePHP::ExceptionInfo::isA(const string& typeId) const
3407 {
3408 if(id == typeId)
3409 {
3410 return true;
3411 }
3412
3413 if(base && base->isA(typeId))
3414 {
3415 return true;
3416 }
3417
3418 return false;
3419 }
3420
3421 //
3422 // ExceptionReader implementation.
3423 //
ExceptionReader(const CommunicatorInfoPtr & communicatorInfo,const ExceptionInfoPtr & info)3424 IcePHP::ExceptionReader::ExceptionReader(const CommunicatorInfoPtr& communicatorInfo, const ExceptionInfoPtr& info
3425 ) :
3426 _communicatorInfo(communicatorInfo), _info(info)
3427 {
3428 }
3429
~ExceptionReader()3430 IcePHP::ExceptionReader::~ExceptionReader()
3431 throw()
3432 {
3433 }
3434
3435 string
ice_id() const3436 IcePHP::ExceptionReader::ice_id() const
3437 {
3438 return _info->id;
3439 }
3440
3441 IcePHP::ExceptionReader*
ice_clone() const3442 IcePHP::ExceptionReader::ice_clone() const
3443 {
3444 assert(false);
3445 return 0;
3446 }
3447
3448 void
ice_throw() const3449 IcePHP::ExceptionReader::ice_throw() const
3450 {
3451 throw *this;
3452 }
3453
3454 void
_write(Ice::OutputStream *) const3455 IcePHP::ExceptionReader::_write(Ice::OutputStream*) const
3456 {
3457 assert(false);
3458 }
3459
3460 void
_read(Ice::InputStream * is)3461 IcePHP::ExceptionReader::_read(Ice::InputStream* is)
3462 {
3463 is->startException();
3464
3465 const_cast<zval*&>(_ex) = _info->unmarshal(is, _communicatorInfo);
3466
3467 const_cast<Ice::SlicedDataPtr&>(_slicedData) = is->endException(_info->preserve);
3468 }
3469
3470 bool
_usesClasses() const3471 IcePHP::ExceptionReader::_usesClasses() const
3472 {
3473 return _info->usesClasses;
3474 }
3475
3476 ExceptionInfoPtr
getInfo() const3477 IcePHP::ExceptionReader::getInfo() const
3478 {
3479 return _info;
3480 }
3481
3482 zval*
getException() const3483 IcePHP::ExceptionReader::getException() const
3484 {
3485 return _ex;
3486 }
3487
3488 Ice::SlicedDataPtr
getSlicedData() const3489 IcePHP::ExceptionReader::getSlicedData() const
3490 {
3491 return _slicedData;
3492 }
3493
3494 //
3495 // IdResolver
3496 //
IdResolver(void)3497 IcePHP::IdResolver::IdResolver(void)
3498 {
3499 }
3500
3501 string
resolve(Ice::Int id) const3502 IcePHP::IdResolver::resolve(Ice::Int id) const
3503 {
3504 CompactIdMap* m = reinterpret_cast<CompactIdMap*>(ICE_G(compactIdToClassInfoMap));
3505 if(m)
3506 {
3507 CompactIdMap::iterator p = m->find(id);
3508 if(p != m->end())
3509 {
3510 return p->second->id;
3511 }
3512 }
3513 return string();
3514 }
3515
3516 #ifdef _WIN32
3517 extern "C"
3518 #endif
3519 static zend_object*
handleTypeInfoAlloc(zend_class_entry * ce)3520 handleTypeInfoAlloc(zend_class_entry* ce)
3521 {
3522 Wrapper<TypeInfoPtr>* obj = Wrapper<TypeInfoPtr>::create(ce);
3523 assert(obj);
3524
3525 obj->zobj.handlers = &_typeInfoHandlers;
3526
3527 return &obj->zobj;
3528 }
3529
3530 #ifdef _WIN32
3531 extern "C"
3532 #endif
3533 static void
handleTypeInfoFreeStorage(zend_object * object)3534 handleTypeInfoFreeStorage(zend_object* object)
3535 {
3536 Wrapper<TypeInfoPtr>* obj = Wrapper<TypeInfoPtr>::fetch(object);
3537 delete obj->ptr;
3538 zend_object_std_dtor(object);
3539 }
3540
3541 static bool
createTypeInfo(zval * zv,const TypeInfoPtr & p)3542 createTypeInfo(zval* zv, const TypeInfoPtr& p)
3543 {
3544 assert(typeInfoClassEntry);
3545 if(object_init_ex(zv, typeInfoClassEntry) != SUCCESS)
3546 {
3547 runtimeError("unable to initialize type");
3548 return false;
3549 }
3550
3551 Wrapper<TypeInfoPtr>* ze = Wrapper<TypeInfoPtr>::extract(zv);
3552 assert(!ze->ptr);
3553 ze->ptr = new TypeInfoPtr(p);
3554
3555 return true;
3556 }
3557
ZEND_FUNCTION(IcePHP_defineEnum)3558 ZEND_FUNCTION(IcePHP_defineEnum)
3559 {
3560 char* id;
3561 size_t idLen;
3562 zval* enumerators;
3563
3564 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("sa"), &id, &idLen, &enumerators) == FAILURE)
3565 {
3566 return;
3567 }
3568
3569 EnumInfoPtr type = new EnumInfo(id, enumerators);
3570
3571 if(!createTypeInfo(return_value, type))
3572 {
3573 RETURN_NULL();
3574 }
3575 }
3576
ZEND_FUNCTION(IcePHP_defineStruct)3577 ZEND_FUNCTION(IcePHP_defineStruct)
3578 {
3579 char* id;
3580 size_t idLen;
3581 char* name;
3582 size_t nameLen;
3583 zval* members;
3584
3585 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("ssa"), &id, &idLen, &name, &nameLen,
3586 &members) == FAILURE)
3587 {
3588 return;
3589 }
3590
3591 StructInfoPtr type = new StructInfo(id, name, members);
3592
3593 if(!createTypeInfo(return_value, type))
3594 {
3595 RETURN_NULL();
3596 }
3597 }
3598
ZEND_FUNCTION(IcePHP_defineSequence)3599 ZEND_FUNCTION(IcePHP_defineSequence)
3600 {
3601 char* id;
3602 size_t idLen;
3603 zval* element;
3604
3605 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("so"), &id, &idLen, &element) == FAILURE)
3606 {
3607 assert(false);
3608 return;
3609 }
3610
3611 SequenceInfoPtr type = new SequenceInfo(id, element);
3612
3613 if(!createTypeInfo(return_value, type))
3614 {
3615 RETURN_NULL();
3616 }
3617 }
3618
ZEND_FUNCTION(IcePHP_defineDictionary)3619 ZEND_FUNCTION(IcePHP_defineDictionary)
3620 {
3621 char* id;
3622 size_t idLen;
3623 zval* key;
3624 zval* value;
3625
3626 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("soo"), &id, &idLen, &key, &value) == FAILURE)
3627 {
3628 return;
3629 }
3630
3631 DictionaryInfoPtr type = new DictionaryInfo(id, key, value);
3632
3633 if(!createTypeInfo(return_value, type))
3634 {
3635 RETURN_NULL();
3636 }
3637 }
3638
ZEND_FUNCTION(IcePHP_declareProxy)3639 ZEND_FUNCTION(IcePHP_declareProxy)
3640 {
3641 char* id;
3642 size_t idLen;
3643
3644 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("s"), &id, &idLen) == FAILURE)
3645 {
3646 return;
3647 }
3648
3649 ProxyInfoPtr type = getProxyInfo(id);
3650 if(!type)
3651 {
3652 type = new ProxyInfo(id);
3653 addProxyInfo(type);
3654 }
3655
3656 if(!createTypeInfo(return_value, type))
3657 {
3658 RETURN_NULL();
3659 }
3660 }
3661
ZEND_FUNCTION(IcePHP_defineProxy)3662 ZEND_FUNCTION(IcePHP_defineProxy)
3663 {
3664 char* id;
3665 size_t idLen;
3666 zval* base;
3667 zval* interfaces;
3668
3669 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("so!a!"), &id, &idLen, &base, &interfaces) == FAILURE)
3670 {
3671 return;
3672 }
3673
3674 ProxyInfoPtr type = getProxyInfo(id);
3675 if(!type)
3676 {
3677 type = new ProxyInfo(id);
3678 addProxyInfo(type);
3679 }
3680 type->define(base, interfaces);
3681
3682 if(!createTypeInfo(return_value, type))
3683 {
3684 RETURN_NULL();
3685 }
3686 }
3687
ZEND_FUNCTION(IcePHP_declareClass)3688 ZEND_FUNCTION(IcePHP_declareClass)
3689 {
3690 char* id;
3691 size_t idLen;
3692
3693 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("s"), &id, &idLen) == FAILURE)
3694 {
3695 return;
3696 }
3697
3698 ClassInfoPtr type = getClassInfoById(id);
3699 if(!type)
3700 {
3701 type = new ClassInfo(id);
3702 addClassInfoById(type);
3703 }
3704
3705 if(!createTypeInfo(return_value, type))
3706 {
3707 RETURN_NULL();
3708 }
3709 }
3710
ZEND_FUNCTION(IcePHP_defineClass)3711 ZEND_FUNCTION(IcePHP_defineClass)
3712 {
3713 char* id;
3714 size_t idLen;
3715 char* name;
3716 size_t nameLen;
3717 zend_long compactId;
3718 zend_bool preserve;
3719 zend_bool interface;
3720 zval* base;
3721 zval* members;
3722
3723 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("sslbbo!a!"), &id, &idLen, &name, &nameLen,
3724 &compactId, &preserve, &interface, &base, &members) == FAILURE)
3725 {
3726 return;
3727 }
3728
3729 ClassInfoPtr type = getClassInfoById(id);
3730 if(!type)
3731 {
3732 type = new ClassInfo(id);
3733 addClassInfoById(type);
3734 }
3735
3736 type->define(name, static_cast<Ice::Int>(compactId), preserve ? true : false, interface ? true : false, base, members);
3737
3738 if(!interface)
3739 {
3740 addClassInfoByName(type);
3741 }
3742
3743 if(type->compactId != -1)
3744 {
3745 CompactIdMap* m = reinterpret_cast<CompactIdMap*>(ICE_G(compactIdToClassInfoMap));
3746 if(!m)
3747 {
3748 m = new CompactIdMap;
3749 ICE_G(compactIdToClassInfoMap) = m;
3750 }
3751 m->insert(CompactIdMap::value_type(type->compactId, type));
3752 }
3753
3754 if(!createTypeInfo(return_value, type))
3755 {
3756 RETURN_NULL();
3757 }
3758 }
3759
3760 #ifdef _WIN32
3761 extern "C"
3762 #endif
3763 static zend_object*
handleExceptionInfoAlloc(zend_class_entry * ce)3764 handleExceptionInfoAlloc(zend_class_entry* ce)
3765 {
3766 Wrapper<ExceptionInfoPtr>* obj = Wrapper<ExceptionInfoPtr>::create(ce);
3767 assert(obj);
3768
3769 obj->zobj.handlers = &_exceptionInfoHandlers;
3770
3771 return &obj->zobj;
3772 }
3773
3774 #ifdef _WIN32
3775 extern "C"
3776 #endif
3777 static void
handleExceptionInfoFreeStorage(zend_object * object)3778 handleExceptionInfoFreeStorage(zend_object* object)
3779 {
3780 Wrapper<ExceptionInfoPtr>* obj = Wrapper<ExceptionInfoPtr>::fetch(object);
3781 delete obj->ptr;
3782 zend_object_std_dtor(object);
3783 }
3784
3785 static bool
createExceptionInfo(zval * zv,const ExceptionInfoPtr & p)3786 createExceptionInfo(zval* zv, const ExceptionInfoPtr& p)
3787 {
3788 if(object_init_ex(zv, exceptionInfoClassEntry) != SUCCESS)
3789 {
3790 runtimeError("unable to initialize exception info");
3791 return false;
3792 }
3793
3794 Wrapper<ExceptionInfoPtr>* ze = Wrapper<ExceptionInfoPtr>::extract(zv);
3795 assert(!ze->ptr);
3796 ze->ptr = new ExceptionInfoPtr(p);
3797
3798 return true;
3799 }
3800
ZEND_FUNCTION(IcePHP_defineException)3801 ZEND_FUNCTION(IcePHP_defineException)
3802 {
3803 char* id;
3804 size_t idLen;
3805 char* name;
3806 size_t nameLen;
3807 zend_bool preserve;
3808 zval* base;
3809 zval* members;
3810
3811 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("ssbo!a!"), &id, &idLen, &name, &nameLen,
3812 &preserve, &base, &members) == FAILURE)
3813 {
3814 return;
3815 }
3816
3817 ExceptionInfoPtr ex = new ExceptionInfo();
3818 ex->id = id;
3819 ex->name = name;
3820 ex->preserve = preserve ? true : false;
3821 if(base)
3822 {
3823 ex->base = Wrapper<ExceptionInfoPtr>::value(base);
3824 }
3825 if(members)
3826 {
3827 convertDataMembers(members, ex->members, ex->optionalMembers, true);
3828 }
3829
3830 ex->usesClasses = false;
3831
3832 //
3833 // Only examine the required members to see if any use classes.
3834 //
3835 for(DataMemberList::iterator p = ex->members.begin(); p != ex->members.end(); ++p)
3836 {
3837 if(!ex->usesClasses)
3838 {
3839 ex->usesClasses = (*p)->type->usesClasses();
3840 }
3841 }
3842
3843 ex->zce = nameToClass(ex->name);
3844
3845 assert(!getExceptionInfo(ex->id));
3846
3847 ExceptionInfoMap* m;
3848 if(ICE_G(exceptionInfoMap))
3849 {
3850 m = reinterpret_cast<ExceptionInfoMap*>(ICE_G(exceptionInfoMap));
3851 }
3852 else
3853 {
3854 m = new ExceptionInfoMap;
3855 ICE_G(exceptionInfoMap) = m;
3856 }
3857 m->insert(ExceptionInfoMap::value_type(ex->id, ex));
3858
3859 if(!createExceptionInfo(return_value, ex))
3860 {
3861 RETURN_NULL();
3862 }
3863 }
3864
ZEND_FUNCTION(IcePHP_stringify)3865 ZEND_FUNCTION(IcePHP_stringify)
3866 {
3867 if(ZEND_NUM_ARGS() != 2)
3868 {
3869 WRONG_PARAM_COUNT;
3870 }
3871
3872 zval* v;
3873 zval* t;
3874
3875 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("zz"), &v, &t) == FAILURE)
3876 {
3877 return;
3878 }
3879
3880 TypeInfoPtr type = Wrapper<TypeInfoPtr>::value(t);
3881 assert(type);
3882
3883 ostringstream ostr;
3884 IceUtilInternal::Output out(ostr);
3885 PrintObjectHistory history;
3886 history.index = 0;
3887 type->print(v, out, &history);
3888
3889 string str = ostr.str();
3890 RETURN_STRINGL(STRCAST(str.c_str()), static_cast<int>(str.length()));
3891 }
3892
ZEND_FUNCTION(IcePHP_stringifyException)3893 ZEND_FUNCTION(IcePHP_stringifyException)
3894 {
3895 if(ZEND_NUM_ARGS() != 2)
3896 {
3897 WRONG_PARAM_COUNT;
3898 }
3899
3900 zval* v;
3901 zval* t;
3902
3903 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("oo"), &v, &t) == FAILURE)
3904 {
3905 return;
3906 }
3907
3908 ExceptionInfoPtr ex = Wrapper<ExceptionInfoPtr>::value(t);
3909 assert(ex);
3910
3911 ostringstream ostr;
3912 IceUtilInternal::Output out(ostr);
3913 ex->print(v, out);
3914
3915 string str = ostr.str();
3916 RETURN_STRINGL(STRCAST(str.c_str()), static_cast<int>(str.length()));
3917 }
3918
3919 //
3920 // Necessary to suppress warnings from zend_function_entry in php-5.2.
3921 //
3922 #if defined(__GNUC__)
3923 # pragma GCC diagnostic ignored "-Wwrite-strings"
3924 #endif
3925
3926 //
3927 // Predefined methods for IcePHP_TypeInfo.
3928 //
3929 static zend_function_entry _typeInfoMethods[] =
3930 {
3931 {0, 0, 0}
3932 };
3933
3934 //
3935 // Predefined methods for IcePHP_ExceptionInfo.
3936 //
3937 static zend_function_entry _exceptionInfoMethods[] =
3938 {
3939 {0, 0, 0}
3940 };
3941
3942 bool
isUnset(zval * zv)3943 IcePHP::isUnset(zval* zv)
3944 {
3945 if(Z_TYPE_P(zv) == IS_STRING)
3946 {
3947 return _unsetGUID == string(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
3948 }
3949 return false;
3950 }
3951
3952 void
assignUnset(zval * zv)3953 IcePHP::assignUnset(zval* zv)
3954 {
3955 ZVAL_DUP(zv, ICE_G(unset));
3956 }
3957
3958 bool
typesInit(INIT_FUNC_ARGS)3959 IcePHP::typesInit(INIT_FUNC_ARGS)
3960 {
3961 zend_class_entry ce;
3962
3963 //
3964 // Register the IcePHP_TypeInfo class.
3965 //
3966 INIT_CLASS_ENTRY(ce, "IcePHP_TypeInfo", _typeInfoMethods);
3967 ce.create_object = handleTypeInfoAlloc;
3968 typeInfoClassEntry = zend_register_internal_class(&ce);
3969 memcpy(&_typeInfoHandlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3970 _typeInfoHandlers.free_obj = handleTypeInfoFreeStorage;
3971 _typeInfoHandlers.offset = XtOffsetOf(Wrapper<TypeInfoPtr>, zobj);
3972
3973 //
3974 // Register the IcePHP_ExceptionInfo class.
3975 //
3976 INIT_CLASS_ENTRY(ce, "IcePHP_ExceptionInfo", _exceptionInfoMethods);
3977 ce.create_object = handleExceptionInfoAlloc;
3978 exceptionInfoClassEntry = zend_register_internal_class(&ce);
3979 memcpy(&_exceptionInfoHandlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
3980 _exceptionInfoHandlers.free_obj = handleExceptionInfoFreeStorage;
3981 _exceptionInfoHandlers.offset = XtOffsetOf(Wrapper<ExceptionInfoPtr>, zobj);
3982
3983 #ifdef ICEPHP_USE_NAMESPACES
3984 REGISTER_NS_STRING_CONSTANT("Ice", "None", const_cast<char*>(_unsetGUID.c_str()), CONST_CS|CONST_PERSISTENT);
3985 #else
3986 REGISTER_STRING_CONSTANT("Ice_Unset", const_cast<char*>(_unsetGUID.c_str()), CONST_CS|CONST_PERSISTENT);
3987 #endif
3988
3989 return true;
3990 }
3991
3992 //
3993 // enable warning again
3994 //
3995 #if defined(__GNUC__)
3996 # pragma GCC diagnostic error "-Wwrite-strings"
3997 #endif
3998
3999 bool
typesRequestInit(void)4000 IcePHP::typesRequestInit(void)
4001 {
4002 //
4003 // Create the global variables for the primitive types.
4004 //
4005 for(int i = static_cast<int>(PrimitiveInfo::KindBool); i <= static_cast<int>(PrimitiveInfo::KindString); ++i)
4006 {
4007 PrimitiveInfoPtr type = new PrimitiveInfo();
4008 type->kind = static_cast<PrimitiveInfo::Kind>(i);
4009
4010 zval zv;
4011 if(!createTypeInfo(&zv, type))
4012 {
4013 zval_ptr_dtor(&zv);
4014 return false;
4015 }
4016 string name = "IcePHP__t_" + type->getId();
4017 zend_hash_str_update(&EG(symbol_table), const_cast<char*>(name.c_str()), name.size(), &zv);
4018 }
4019
4020 ICE_G(idToClassInfoMap) = 0;
4021 ICE_G(nameToClassInfoMap) = 0;
4022 ICE_G(proxyInfoMap) = 0;
4023 ICE_G(exceptionInfoMap) = 0;
4024
4025 zval* unset = static_cast<zval*>(emalloc(sizeof(zval)));
4026 ZVAL_STRINGL(unset, STRCAST(_unsetGUID.c_str()), static_cast<int>(_unsetGUID.length()));
4027 ICE_G(unset) = unset;
4028
4029 return true;
4030 }
4031
4032 bool
typesRequestShutdown(void)4033 IcePHP::typesRequestShutdown(void)
4034 {
4035 if(ICE_G(proxyInfoMap))
4036 {
4037 ProxyInfoMap* m = static_cast<ProxyInfoMap*>(ICE_G(proxyInfoMap));
4038 for(ProxyInfoMap::iterator p = m->begin(); p != m->end(); ++p)
4039 {
4040 p->second->destroy();
4041 }
4042 delete m;
4043 }
4044
4045 if(ICE_G(idToClassInfoMap))
4046 {
4047 ClassInfoMap* m = static_cast<ClassInfoMap*>(ICE_G(idToClassInfoMap));
4048 for(ClassInfoMap::iterator p = m->begin(); p != m->end(); ++p)
4049 {
4050 p->second->destroy();
4051 }
4052 delete m;
4053 }
4054
4055 if(ICE_G(nameToClassInfoMap))
4056 {
4057 ClassInfoMap* m = static_cast<ClassInfoMap*>(ICE_G(nameToClassInfoMap));
4058 delete m;
4059 }
4060
4061 delete static_cast<ExceptionInfoMap*>(ICE_G(exceptionInfoMap));
4062
4063 zval_dtor(ICE_G(unset));
4064 efree(ICE_G(unset));
4065 return true;
4066 }
4067