summaryrefslogtreecommitdiff
path: root/php/src/php5/Util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'php/src/php5/Util.cpp')
-rw-r--r--php/src/php5/Util.cpp1034
1 files changed, 1034 insertions, 0 deletions
diff --git a/php/src/php5/Util.cpp b/php/src/php5/Util.cpp
new file mode 100644
index 00000000000..2d81667eb60
--- /dev/null
+++ b/php/src/php5/Util.cpp
@@ -0,0 +1,1034 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <Util.h>
+#include <IceUtil/UUID.h>
+#include <Slice/PHPUtil.h>
+#include <algorithm>
+#include <ctype.h>
+
+using namespace std;
+using namespace IcePHP;
+using namespace Slice::PHP;
+
+namespace
+{
+
+bool
+getMember(zval* zv, const string& name, zval** member, int type, bool required TSRMLS_DC)
+{
+ *member = 0;
+
+ void* data = 0;
+ if(zend_hash_find(Z_OBJPROP_P(zv), STRCAST(name.c_str()), name.size() + 1, &data) == FAILURE)
+ {
+ if(required)
+ {
+ invalidArgument("object does not contain member `%s'" TSRMLS_CC, name.c_str());
+ return false;
+ }
+ }
+
+ if(data)
+ {
+ zval** val = reinterpret_cast<zval**>(data);
+
+ if(Z_TYPE_PP(val) != type)
+ {
+ string expected = zendTypeToString(type);
+ string actual = zendTypeToString(Z_TYPE_PP(val));
+ invalidArgument("expected value of type %s for member `%s' but received %s" TSRMLS_CC, expected.c_str(),
+ name.c_str(), actual.c_str());
+ return false;
+ }
+
+ *member = *val;
+ }
+
+ return true;
+}
+
+void
+setStringMember(zval* obj, const string& name, const string& val TSRMLS_DC)
+{
+ zend_class_entry* cls = Z_OBJCE_P(obj);
+ assert(cls);
+ zend_update_property_stringl(cls, obj, const_cast<char*>(name.c_str()), static_cast<int>(name.size()),
+ const_cast<char*>(val.c_str()), static_cast<int>(val.size()) TSRMLS_CC);
+}
+
+template<typename T>
+bool
+getVersion(zval* zv, T& v, const char* type TSRMLS_DC)
+{
+ if(Z_TYPE_P(zv) != IS_OBJECT)
+ {
+ invalidArgument("value does not contain an object" TSRMLS_CC);
+ return false;
+ }
+
+ zend_class_entry* cls = idToClass(type TSRMLS_CC);
+ assert(cls);
+
+ zend_class_entry* ce = Z_OBJCE_P(zv);
+ if(ce != cls)
+ {
+ invalidArgument("expected an instance of %s" TSRMLS_CC, ce->name);
+ return false;
+ }
+
+ zval* majorVal;
+ if(!getMember(zv, "major", &majorVal, IS_LONG, true TSRMLS_CC))
+ {
+ return false;
+ }
+
+ zval* minorVal;
+ if(!getMember(zv, "minor", &minorVal, IS_LONG, true TSRMLS_CC))
+ {
+ return false;
+ }
+
+ long m;
+ m = Z_LVAL_P(majorVal);
+ if(m < 0 || m > 255)
+ {
+ invalidArgument("version major must be a value between 0 and 255" TSRMLS_CC);
+ return false;
+ }
+ v.major = static_cast<Ice::Byte>(m);
+
+ m = Z_LVAL_P(minorVal);
+ if(m < 0 || m > 255)
+ {
+ invalidArgument("version minor must be a value between 0 and 255" TSRMLS_CC);
+ return false;
+ }
+ v.minor = static_cast<Ice::Byte>(m);
+
+ return true;
+}
+
+template<typename T>
+bool
+createVersion(zval* zv, const T& version, const char* type TSRMLS_DC)
+{
+ zend_class_entry* cls = idToClass(type TSRMLS_CC);
+ assert(cls);
+
+ if(object_init_ex(zv, cls) != SUCCESS)
+ {
+ runtimeError("unable to initialize %s" TSRMLS_CC, cls->name);
+ return false;
+ }
+
+ zend_update_property_long(cls, zv, const_cast<char*>("major"), sizeof("major") - 1, version.major TSRMLS_CC);
+ zend_update_property_long(cls, zv, const_cast<char*>("minor"), sizeof("minor") - 1, version.minor TSRMLS_CC);
+
+ return true;
+}
+
+template<typename T>
+bool
+versionToString(zval* zv, zval* s, const char* type TSRMLS_DC)
+{
+ T v;
+ if(!getVersion<T>(zv, v, type TSRMLS_CC))
+ {
+ return false;
+ }
+
+ try
+ {
+ string str = IceInternal::versionToString<T>(v);
+ ZVAL_STRINGL(s, STRCAST(str.c_str()), static_cast<int>(str.length()), 1);
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ return false;
+ }
+
+ return true;
+}
+
+template<typename T>
+bool
+stringToVersion(const string& s, zval* zv, const char* type TSRMLS_DC)
+{
+ try
+ {
+ T v = IceInternal::stringToVersion<T>(s);
+ return createVersion<T>(zv, v, type TSRMLS_CC);
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ throwException(ex TSRMLS_CC);
+ }
+
+ return false;
+}
+
+char Ice_ProtocolVersion[] = "::Ice::ProtocolVersion";
+char Ice_EncodingVersion[] = "::Ice::EncodingVersion";
+
+}
+
+#if PHP_VERSION_ID < 50400
+#ifdef _WIN32
+extern "C"
+#endif
+static void
+dtor_wrapper(void* p)
+{
+ zval_ptr_dtor(static_cast<zval**>(p));
+}
+#endif
+
+void*
+IcePHP::createWrapper(zend_class_entry* ce, size_t sz TSRMLS_DC)
+{
+ zend_object* obj;
+
+ obj = static_cast<zend_object*>(emalloc(sz));
+
+ zend_object_std_init(obj, ce TSRMLS_CC);
+
+#if PHP_VERSION_ID < 50400
+ zval* tmp;
+ obj->properties = static_cast<HashTable*>(emalloc(sizeof(HashTable)));
+ zend_hash_init(obj->properties, 0, 0, dtor_wrapper, 0);
+ zend_hash_copy(obj->properties, &ce->default_properties, (copy_ctor_func_t)zval_add_ref, &tmp, sizeof(zval*));
+#else
+ object_properties_init(obj, ce);
+#endif
+
+ return obj;
+}
+
+void*
+IcePHP::extractWrapper(zval* zv TSRMLS_DC)
+{
+ if(!zv)
+ {
+ runtimeError("method %s() must be invoked on an object" TSRMLS_CC, get_active_function_name(TSRMLS_C));
+ return 0;
+ }
+
+ zend_object* obj = static_cast<zend_object*>(zend_object_store_get_object(zv TSRMLS_CC));
+ if(!obj)
+ {
+ runtimeError("no object found in %s()" TSRMLS_CC, get_active_function_name(TSRMLS_C));
+ return 0;
+ }
+
+ return obj;
+}
+
+zend_class_entry*
+IcePHP::idToClass(const string& id TSRMLS_DC)
+{
+#ifdef ICEPHP_USE_NAMESPACES
+ string cls = scopedToName(id, true);
+#else
+ string cls = scopedToName(id, false);
+#endif
+
+ return nameToClass(cls TSRMLS_CC);
+}
+
+zend_class_entry*
+IcePHP::nameToClass(const string& name TSRMLS_DC)
+{
+ zend_class_entry** result;
+ if(zend_lookup_class(STRCAST(name.c_str()), static_cast<int>(name.length()), &result TSRMLS_CC) == FAILURE)
+ {
+ return 0;
+ }
+ return *result;
+}
+
+bool
+IcePHP::createIdentity(zval* zv, const Ice::Identity& id TSRMLS_DC)
+{
+ zend_class_entry* cls = idToClass("::Ice::Identity" TSRMLS_CC);
+ assert(cls);
+
+ if(object_init_ex(zv, cls) != SUCCESS)
+ {
+ runtimeError("unable to initialize Ice::Identity" TSRMLS_CC);
+ return false;
+ }
+
+ setStringMember(zv, "name", id.name TSRMLS_CC);
+ setStringMember(zv, "category", id.category TSRMLS_CC);
+
+ return true;
+}
+
+bool
+IcePHP::extractIdentity(zval* zv, Ice::Identity& id TSRMLS_DC)
+{
+ if(Z_TYPE_P(zv) != IS_OBJECT)
+ {
+ invalidArgument("value does not contain an object" TSRMLS_CC);
+ return false;
+ }
+
+ zend_class_entry* cls = idToClass("::Ice::Identity" TSRMLS_CC);
+ assert(cls);
+
+ zend_class_entry* ce = Z_OBJCE_P(zv);
+ if(ce != cls)
+ {
+ invalidArgument("expected an identity but received %s" TSRMLS_CC, ce->name);
+ return false;
+ }
+
+ //
+ // Category is optional, but name is required.
+ //
+ zval* categoryVal;
+ zval* nameVal;
+
+ if(!getMember(zv, "category", &categoryVal, IS_STRING, false TSRMLS_CC) ||
+ !getMember(zv, "name", &nameVal, IS_STRING, true TSRMLS_CC))
+ {
+ return false;
+ }
+
+ id.name = Z_STRVAL_P(nameVal);
+ if(categoryVal)
+ {
+ id.category = Z_STRVAL_P(categoryVal);
+ }
+ else
+ {
+ id.category = "";
+ }
+
+ return true;
+}
+
+bool
+IcePHP::createStringMap(zval* zv, const map<string, string>& ctx TSRMLS_DC)
+{
+ array_init(zv);
+ for(map<string, string>::const_iterator p = ctx.begin(); p != ctx.end(); ++p)
+ {
+ if(add_assoc_stringl_ex(zv, const_cast<char*>(p->first.c_str()), p->first.length() + 1,
+ const_cast<char*>(p->second.c_str()),
+ static_cast<uint>(p->second.length()), 1) == FAILURE)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+IcePHP::extractStringMap(zval* zv, map<string, string>& ctx TSRMLS_DC)
+{
+ if(Z_TYPE_P(zv) != IS_ARRAY)
+ {
+ string s = zendTypeToString(Z_TYPE_P(zv));
+ invalidArgument("expected an associative array but received %s" TSRMLS_CC, s.c_str());
+ return false;
+ }
+
+ HashTable* arr = Z_ARRVAL_P(zv);
+ void* data;
+ HashPosition pos;
+
+ zend_hash_internal_pointer_reset_ex(arr, &pos);
+ while(zend_hash_get_current_data_ex(arr, &data, &pos) != FAILURE)
+ {
+ zval** val = reinterpret_cast<zval**>(data);
+
+ //
+ // Get the key (which can be a long or a string).
+ //
+ char* keyStr;
+ uint keyLen;
+ ulong keyNum;
+ int keyType = zend_hash_get_current_key_ex(arr, &keyStr, &keyLen, &keyNum, 0, &pos);
+
+ //
+ // Store the key in a zval, so that we can reuse the PrimitiveMarshaler logic.
+ //
+ if(keyType != HASH_KEY_IS_STRING)
+ {
+ invalidArgument("array key must be a string" TSRMLS_CC);
+ return false;
+ }
+
+ if(Z_TYPE_PP(val) != IS_STRING)
+ {
+ invalidArgument("array value must be a string" TSRMLS_CC);
+ return false;
+ }
+
+ ctx[keyStr] = Z_STRVAL_PP(val);
+
+ zend_hash_move_forward_ex(arr, &pos);
+ }
+
+ return true;
+}
+
+bool
+IcePHP::createStringArray(zval* zv, const Ice::StringSeq& seq TSRMLS_DC)
+{
+ array_init(zv);
+ for(Ice::StringSeq::const_iterator p = seq.begin(); p != seq.end(); ++p)
+ {
+ if(add_next_index_stringl(zv, STRCAST(p->c_str()), static_cast<uint>(p->length()), 1) == FAILURE)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+IcePHP::extractStringArray(zval* zv, Ice::StringSeq& seq TSRMLS_DC)
+{
+ if(Z_TYPE_P(zv) != IS_ARRAY)
+ {
+ string s = zendTypeToString(Z_TYPE_P(zv));
+ invalidArgument("expected an array of strings but received %s" TSRMLS_CC, s.c_str());
+ return false;
+ }
+
+ HashTable* arr = Z_ARRVAL_P(zv);
+ void* data;
+ HashPosition pos;
+
+ zend_hash_internal_pointer_reset_ex(arr, &pos);
+ while(zend_hash_get_current_data_ex(arr, &data, &pos) != FAILURE)
+ {
+ zval** val = reinterpret_cast<zval**>(data);
+
+ if(Z_TYPE_PP(val) != IS_STRING)
+ {
+ invalidArgument("array element must be a string" TSRMLS_CC);
+ return false;
+ }
+
+ string s(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
+ seq.push_back(s);
+
+ zend_hash_move_forward_ex(arr, &pos);
+ }
+
+ return true;
+}
+
+bool
+IcePHP::createProtocolVersion(zval* zv, const Ice::ProtocolVersion& v TSRMLS_DC)
+{
+ return createVersion<Ice::ProtocolVersion>(zv, v, Ice_ProtocolVersion TSRMLS_CC);
+}
+
+bool
+IcePHP::createEncodingVersion(zval* zv, const Ice::EncodingVersion& v TSRMLS_DC)
+{
+ return createVersion<Ice::EncodingVersion>(zv, v, Ice_EncodingVersion TSRMLS_CC);
+}
+
+bool
+IcePHP::extractEncodingVersion(zval* zv, Ice::EncodingVersion& v TSRMLS_DC)
+{
+ return getVersion<Ice::EncodingVersion>(zv, v, Ice_EncodingVersion TSRMLS_CC);
+}
+
+static bool
+convertLocalException(const Ice::LocalException& ex, zval* zex TSRMLS_DC)
+{
+ zend_class_entry* cls = Z_OBJCE_P(zex);
+ assert(cls);
+
+ //
+ // Transfer data members from Ice exception to PHP object.
+ //
+ try
+ {
+ ex.ice_throw();
+ }
+ catch(const Ice::InitializationException& e)
+ {
+ setStringMember(zex, "reason", e.reason TSRMLS_CC);
+ }
+ catch(const Ice::PluginInitializationException& e)
+ {
+ setStringMember(zex, "reason", e.reason TSRMLS_CC);
+ }
+ catch(const Ice::AlreadyRegisteredException& e)
+ {
+ setStringMember(zex, "kindOfObject", e.kindOfObject TSRMLS_CC);
+ setStringMember(zex, "id", e.id TSRMLS_CC);
+ }
+ catch(const Ice::NotRegisteredException& e)
+ {
+ setStringMember(zex, "kindOfObject", e.kindOfObject TSRMLS_CC);
+ setStringMember(zex, "id", e.id TSRMLS_CC);
+ }
+ catch(const Ice::TwowayOnlyException& e)
+ {
+ setStringMember(zex, "operation", e.operation TSRMLS_CC);
+ }
+ catch(const Ice::UnknownException& e)
+ {
+ setStringMember(zex, "unknown", e.unknown TSRMLS_CC);
+ }
+ catch(const Ice::ObjectAdapterDeactivatedException& e)
+ {
+ setStringMember(zex, "name", e.name TSRMLS_CC);
+ }
+ catch(const Ice::ObjectAdapterIdInUseException& e)
+ {
+ setStringMember(zex, "id", e.id TSRMLS_CC);
+ }
+ catch(const Ice::NoEndpointException& e)
+ {
+ setStringMember(zex, "proxy", e.proxy TSRMLS_CC);
+ }
+ catch(const Ice::EndpointParseException& e)
+ {
+ setStringMember(zex, "str", e.str TSRMLS_CC);
+ }
+ catch(const Ice::IdentityParseException& e)
+ {
+ setStringMember(zex, "str", e.str TSRMLS_CC);
+ }
+ catch(const Ice::ProxyParseException& e)
+ {
+ setStringMember(zex, "str", e.str TSRMLS_CC);
+ }
+ catch(const Ice::IllegalIdentityException& e)
+ {
+ zval* id;
+ MAKE_STD_ZVAL(id);
+ if(!createIdentity(id, e.id TSRMLS_CC))
+ {
+ zval_ptr_dtor(&id);
+ return false;
+ }
+ zend_update_property(cls, zex, const_cast<char*>("id"), sizeof("id") - 1, id TSRMLS_CC);
+ zval_ptr_dtor(&id);
+ }
+ catch(const Ice::RequestFailedException& e)
+ {
+ zval* id;
+ MAKE_STD_ZVAL(id);
+ if(!createIdentity(id, e.id TSRMLS_CC))
+ {
+ zval_ptr_dtor(&id);
+ return false;
+ }
+ zend_update_property(cls, zex, const_cast<char*>("id"), sizeof("id") - 1, id TSRMLS_CC);
+ zval_ptr_dtor(&id);
+ setStringMember(zex, "facet", e.facet TSRMLS_CC);
+ setStringMember(zex, "operation", e.operation TSRMLS_CC);
+ }
+ catch(const Ice::FileException& e)
+ {
+ zend_update_property_long(cls, zex, const_cast<char*>("error"), sizeof("error") - 1, e.error TSRMLS_CC);
+ setStringMember(zex, "path", e.path TSRMLS_CC);
+ }
+ catch(const Ice::SyscallException& e) // This must appear after all subclasses of SyscallException.
+ {
+ zend_update_property_long(cls, zex, const_cast<char*>("error"), sizeof("error") - 1, e.error TSRMLS_CC);
+ }
+ catch(const Ice::DNSException& e)
+ {
+ zend_update_property_long(cls, zex, const_cast<char*>("error"), sizeof("error") - 1, e.error TSRMLS_CC);
+ setStringMember(zex, "host", e.host TSRMLS_CC);
+ }
+ catch(const Ice::UnsupportedProtocolException& e)
+ {
+ zval* v;
+ MAKE_STD_ZVAL(v);
+ if(!createProtocolVersion(v, e.bad TSRMLS_CC))
+ {
+ zval_ptr_dtor(&v);
+ return false;
+ }
+ zend_update_property(cls, zex, const_cast<char*>("bad"), sizeof("bad") - 1, v TSRMLS_CC);
+ zval_ptr_dtor(&v);
+
+ MAKE_STD_ZVAL(v);
+ if(!createProtocolVersion(v, e.supported TSRMLS_CC))
+ {
+ zval_ptr_dtor(&v);
+ return false;
+ }
+ zend_update_property(cls, zex, const_cast<char*>("supported"), sizeof("supported") - 1, v TSRMLS_CC);
+ zval_ptr_dtor(&v);
+ }
+ catch(const Ice::UnsupportedEncodingException& e)
+ {
+ zval* v;
+ MAKE_STD_ZVAL(v);
+ if(!createEncodingVersion(v, e.bad TSRMLS_CC))
+ {
+ zval_ptr_dtor(&v);
+ return false;
+ }
+ zend_update_property(cls, zex, const_cast<char*>("bad"), sizeof("bad") - 1, v TSRMLS_CC);
+ zval_ptr_dtor(&v);
+
+ MAKE_STD_ZVAL(v);
+ if(!createEncodingVersion(v, e.supported TSRMLS_CC))
+ {
+ zval_ptr_dtor(&v);
+ return false;
+ }
+ zend_update_property(cls, zex, const_cast<char*>("supported"), sizeof("supported") - 1, v TSRMLS_CC);
+ zval_ptr_dtor(&v);
+ }
+ catch(const Ice::NoObjectFactoryException& e)
+ {
+ setStringMember(zex, "reason", e.reason TSRMLS_CC);
+ setStringMember(zex, "type", e.type TSRMLS_CC);
+ }
+ catch(const Ice::UnexpectedObjectException& e)
+ {
+ setStringMember(zex, "reason", e.reason TSRMLS_CC);
+ setStringMember(zex, "type", e.type TSRMLS_CC);
+ setStringMember(zex, "expectedType", e.expectedType TSRMLS_CC);
+ }
+ catch(const Ice::ProtocolException& e) // This must appear after all subclasses of ProtocolException.
+ {
+ setStringMember(zex, "reason", e.reason TSRMLS_CC);
+ }
+ catch(const Ice::FeatureNotSupportedException& e)
+ {
+ setStringMember(zex, "unsupportedFeature", e.unsupportedFeature TSRMLS_CC);
+ }
+ catch(const Ice::SecurityException& e)
+ {
+ setStringMember(zex, "reason", e.reason TSRMLS_CC);
+ }
+ catch(const Ice::LocalException&)
+ {
+ //
+ // Nothing to do.
+ //
+ }
+
+ return true;
+}
+
+zval*
+IcePHP::convertException(const Ice::Exception& ex TSRMLS_DC)
+{
+ zval* zex;
+ MAKE_STD_ZVAL(zex);
+ AutoDestroy destroy(zex);
+
+ ostringstream ostr;
+ ostr << ex;
+ string str = ostr.str();
+
+ try
+ {
+ ex.ice_throw();
+ }
+ catch(const Ice::LocalException& e)
+ {
+ zend_class_entry* cls = idToClass(e.ice_name() TSRMLS_CC);
+ if(cls)
+ {
+ if(object_init_ex(zex, cls) != SUCCESS)
+ {
+ runtimeError("unable to create exception %s" TSRMLS_CC, cls->name);
+ return 0;
+ }
+ if(!convertLocalException(e, zex TSRMLS_CC))
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ cls = idToClass("Ice::UnknownLocalException" TSRMLS_CC);
+ assert(cls);
+ if(object_init_ex(zex, cls) != SUCCESS)
+ {
+ runtimeError("unable to create exception %s" TSRMLS_CC, cls->name);
+ return 0;
+ }
+ setStringMember(zex, "unknown", str TSRMLS_CC);
+ }
+ }
+ catch(const Ice::UserException&)
+ {
+ zend_class_entry* cls = idToClass("Ice::UnknownUserException" TSRMLS_CC);
+ assert(cls);
+ if(object_init_ex(zex, cls) != SUCCESS)
+ {
+ runtimeError("unable to create exception %s" TSRMLS_CC, cls->name);
+ return 0;
+ }
+ setStringMember(zex, "unknown", str TSRMLS_CC);
+ }
+ catch(const Ice::Exception&)
+ {
+ zend_class_entry* cls = idToClass("Ice::UnknownException" TSRMLS_CC);
+ assert(cls);
+ if(object_init_ex(zex, cls) != SUCCESS)
+ {
+ runtimeError("unable to create exception %s" TSRMLS_CC, cls->name);
+ return 0;
+ }
+ setStringMember(zex, "unknown", str TSRMLS_CC);
+ }
+
+ return destroy.release();
+}
+
+void
+IcePHP::throwException(const Ice::Exception& ex TSRMLS_DC)
+{
+ zval* zex = convertException(ex TSRMLS_CC);
+ if(zex)
+ {
+ zend_throw_exception_object(zex TSRMLS_CC);
+ }
+}
+
+std::string
+IcePHP::zendTypeToString(int type)
+{
+ string result;
+
+ switch(type)
+ {
+ case IS_NULL:
+ result = "null";
+ break;
+
+ case IS_LONG:
+ result = "long";
+ break;
+
+ case IS_DOUBLE:
+ result = "double";
+ break;
+
+ case IS_STRING:
+ result = "string";
+ break;
+
+ case IS_ARRAY:
+ result = "array";
+ break;
+
+ case IS_OBJECT:
+ result = "object";
+ break;
+
+ case IS_BOOL:
+ result = "bool";
+ break;
+
+ default:
+ result = "unknown";
+ break;
+ }
+
+ return result;
+}
+
+static void
+throwError(const string& name, const string& msg TSRMLS_DC)
+{
+ zval* ex;
+ MAKE_STD_ZVAL(ex);
+ AutoDestroy destroy(ex);
+
+ zend_class_entry* cls;
+ {
+ zend_class_entry** p;
+ if(zend_lookup_class(STRCAST(name.c_str()), static_cast<int>(name.size()), &p TSRMLS_CC) == FAILURE)
+ {
+ assert(false);
+ }
+ cls = *p;
+ }
+ if(object_init_ex(ex, cls) == FAILURE)
+ {
+ assert(false);
+ }
+
+ //
+ // Invoke constructor.
+ //
+ if(!invokeMethod(ex, ZEND_CONSTRUCTOR_FUNC_NAME, msg TSRMLS_CC))
+ {
+ assert(false);
+ }
+
+ zend_throw_exception_object(ex TSRMLS_CC);
+ destroy.release();
+}
+
+void
+IcePHP::runtimeError(const char* fmt TSRMLS_DC, ...)
+{
+ va_list args;
+ char msg[1024];
+
+#if ZTS
+ va_start(args, TSRMLS_C);
+#else
+ va_start(args, fmt);
+#endif
+
+#if defined(_MSC_VER)
+ vsprintf_s(msg, fmt, args);
+#else
+ vsprintf(msg, fmt, args);
+#endif
+
+ va_end(args);
+
+ throwError("RuntimeException", msg TSRMLS_CC);
+}
+
+void
+IcePHP::invalidArgument(const char* fmt TSRMLS_DC, ...)
+{
+ va_list args;
+ char msg[1024];
+
+#if ZTS
+ va_start(args, TSRMLS_C);
+#else
+ va_start(args, fmt);
+#endif
+
+#if defined(_MSC_VER)
+ vsprintf_s(msg, fmt, args);
+#else
+ vsprintf(msg, fmt, args);
+#endif
+
+ va_end(args);
+
+ throwError("InvalidArgumentException", msg TSRMLS_CC);
+}
+
+static bool
+invokeMethodHelper(zval* obj, const string& name, zval* param TSRMLS_DC)
+{
+ assert(zend_hash_exists(&Z_OBJCE_P(obj)->function_table, STRCAST(name.c_str()), name.size() + 1));
+ zval ret, method;
+ INIT_ZVAL(ret);
+ INIT_ZVAL(method);
+ ZVAL_STRING(&method, STRCAST(name.c_str()), 1);
+ zend_uint numParams = param ? 1 : 0;
+ zval** params = param ? &param : 0;
+ int status = 0;
+ zend_try
+ {
+ status = call_user_function(0, &obj, &method, &ret, numParams, params TSRMLS_CC);
+ }
+ zend_catch
+ {
+ status = FAILURE;
+ }
+ zend_end_try();
+ zval_dtor(&method);
+ zval_dtor(&ret);
+ if(status == FAILURE || EG(exception))
+ {
+ return false;
+ }
+ return true;
+}
+
+bool
+IcePHP::invokeMethod(zval* obj, const string& name TSRMLS_DC)
+{
+ return invokeMethodHelper(obj, name, 0 TSRMLS_CC);
+}
+
+bool
+IcePHP::invokeMethod(zval* obj, const string& name, const string& arg TSRMLS_DC)
+{
+ zval* param;
+ MAKE_STD_ZVAL(param);
+ ZVAL_STRINGL(param, STRCAST(arg.c_str()), static_cast<int>(arg.size()), 1);
+ AutoDestroy destroy(param);
+ return invokeMethodHelper(obj, name, param TSRMLS_CC);
+}
+
+bool
+IcePHP::checkClass(zend_class_entry* ce, zend_class_entry* base)
+{
+ while(ce)
+ {
+ if(ce == base)
+ {
+ return true;
+ }
+
+ for(zend_uint i = 0; i < ce->num_interfaces; ++i)
+ {
+ if(checkClass(ce->interfaces[i], base))
+ {
+ return true;
+ }
+ }
+
+ ce = ce->parent;
+ }
+
+ return false;
+}
+
+ZEND_FUNCTION(Ice_stringVersion)
+{
+ if(ZEND_NUM_ARGS() > 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ RETURN_STRINGL(STRCAST(ICE_STRING_VERSION), static_cast<int>(strlen(ICE_STRING_VERSION)), 1);
+}
+
+ZEND_FUNCTION(Ice_intVersion)
+{
+ if(ZEND_NUM_ARGS() > 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ RETURN_LONG(ICE_INT_VERSION);
+}
+
+ZEND_FUNCTION(Ice_generateUUID)
+{
+ if(ZEND_NUM_ARGS() > 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ string uuid = IceUtil::generateUUID();
+ RETURN_STRINGL(STRCAST(uuid.c_str()), static_cast<int>(uuid.size()), 1);
+}
+
+ZEND_FUNCTION(Ice_currentProtocol)
+{
+ if(ZEND_NUM_ARGS() > 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ if(!createProtocolVersion(return_value, Ice::currentProtocol TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}
+
+ZEND_FUNCTION(Ice_currentProtocolEncoding)
+{
+ if(ZEND_NUM_ARGS() > 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ if(!createEncodingVersion(return_value, Ice::currentProtocolEncoding TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}
+
+ZEND_FUNCTION(Ice_currentEncoding)
+{
+ if(ZEND_NUM_ARGS() > 0)
+ {
+ WRONG_PARAM_COUNT;
+ }
+
+ if(!createEncodingVersion(return_value, Ice::currentEncoding TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}
+
+ZEND_FUNCTION(Ice_protocolVersionToString)
+{
+ zend_class_entry* versionClass = idToClass(Ice_ProtocolVersion TSRMLS_CC);
+ assert(versionClass);
+
+ zval* zv;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("O"), &zv, versionClass) != SUCCESS)
+ {
+ RETURN_NULL();
+ }
+
+ if(!versionToString<Ice::ProtocolVersion>(zv, return_value, Ice_ProtocolVersion TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}
+
+ZEND_FUNCTION(Ice_stringToProtocolVersion)
+{
+ char* str;
+ int strLen;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s"), &str, &strLen) != SUCCESS)
+ {
+ RETURN_NULL();
+ }
+ string s(str, strLen);
+
+ if(!stringToVersion<Ice::ProtocolVersion>(s, return_value, Ice_ProtocolVersion TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}
+
+ZEND_FUNCTION(Ice_encodingVersionToString)
+{
+ zend_class_entry* versionClass = idToClass(Ice_EncodingVersion TSRMLS_CC);
+ assert(versionClass);
+
+ zval* zv;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("O"), &zv, versionClass) != SUCCESS)
+ {
+ RETURN_NULL();
+ }
+
+ if(!versionToString<Ice::EncodingVersion>(zv, return_value, Ice_EncodingVersion TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}
+
+ZEND_FUNCTION(Ice_stringToEncodingVersion)
+{
+ char* str;
+ int strLen;
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s"), &str, &strLen) != SUCCESS)
+ {
+ RETURN_NULL();
+ }
+ string s(str, strLen);
+
+ if(!stringToVersion<Ice::EncodingVersion>(s, return_value, Ice_EncodingVersion TSRMLS_CC))
+ {
+ RETURN_NULL();
+ }
+}