diff options
author | Mark Spruiell <mes@zeroc.com> | 2012-10-12 15:31:48 -0700 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2012-10-12 15:31:48 -0700 |
commit | ed09446f6ab09a14abbbf3080bfa5986927a070d (patch) | |
tree | 4b3735e7b7b1c2ffe8056f7b9be7adbeb4d50f16 | |
parent | WinRT port updates (diff) | |
download | ice-ed09446f6ab09a14abbbf3080bfa5986927a070d.tar.bz2 ice-ed09446f6ab09a14abbbf3080bfa5986927a070d.tar.xz ice-ed09446f6ab09a14abbbf3080bfa5986927a070d.zip |
PHP optionals
26 files changed, 2452 insertions, 557 deletions
diff --git a/cpp/src/slice2php/Main.cpp b/cpp/src/slice2php/Main.cpp index 2d9bb5109c4..dc2453fb77c 100644 --- a/cpp/src/slice2php/Main.cpp +++ b/cpp/src/slice2php/Main.cpp @@ -149,7 +149,7 @@ CodeVisitor::visitClassDecl(const ClassDeclPtr& p) _out << nl << type << " = IcePHP_declareClass('" << scoped << "');"; if(!p->isLocal()) { - _out << nl << type << "Prx = IcePHP_defineProxy(" << type << ");"; + _out << nl << type << "Prx = IcePHP_declareProxy('" << scoped << "');"; } _out << eb; @@ -382,6 +382,10 @@ CodeVisitor::visitClassDefStart(const ClassDefPtr& p) // Emit a forward declaration for the class in case a data member refers to this type. // _out << sp << nl << type << " = IcePHP_declareClass('" << scoped << "');"; + if(!p->isLocal()) + { + _out << nl << prxType << " = IcePHP_declareProxy('" << scoped << "');"; + } } // @@ -425,7 +429,7 @@ CodeVisitor::visitClassDefStart(const ClassDefPtr& p) // // Data members are represented as an array: // - // ('MemberName', MemberType) + // ('MemberName', MemberType, Optional, Tag) // // where MemberType is either a primitive type constant (T_INT, etc.) or the id of a constructed type. // @@ -436,12 +440,13 @@ CodeVisitor::visitClassDefStart(const ClassDefPtr& p) { if(q != members.begin()) { - _out << ',' << nl; + _out << ','; } _out.inc(); _out << nl << "array('" << fixIdent((*q)->name()) << "', "; writeType((*q)->type()); - _out << ')'; + _out << ", " << ((*q)->optional() ? "true" : "false") << ", " + << ((*q)->optional() ? (*q)->tag() : 0) << ')'; _out.dec(); } _out << ')'; @@ -459,7 +464,7 @@ CodeVisitor::visitClassDefStart(const ClassDefPtr& p) // // Define each operation. The arguments to IcePHP_defineOperation are: // - // $ClassType, 'opName', Mode, SendMode, FormatType, (InParams), (OutParams), ReturnType, (Exceptions) + // $ClassType, 'opName', Mode, SendMode, FormatType, (InParams), (OutParams), ReturnParam, (Exceptions) // // where InParams and OutParams are arrays of type descriptions, and Exceptions // is an array of exception type ids. @@ -488,7 +493,10 @@ CodeVisitor::visitClassDefStart(const ClassDefPtr& p) { _out << ", "; } + _out << "array("; writeType((*t)->type()); + _out << ", " << ((*t)->optional() ? "true" : "false") << ", " + << ((*t)->optional() ? (*t)->tag() : 0) << ')'; ++count; } } @@ -513,7 +521,10 @@ CodeVisitor::visitClassDefStart(const ClassDefPtr& p) { _out << ", "; } + _out << "array("; writeType((*t)->type()); + _out << ", " << ((*t)->optional() ? "true" : "false") << ", " + << ((*t)->optional() ? (*t)->tag() : 0) << ')'; ++count; } } @@ -529,7 +540,15 @@ CodeVisitor::visitClassDefStart(const ClassDefPtr& p) TypePtr returnType = (*oli)->returnType(); if(returnType) { + // + // The return type has the same format as an in/out parameter: + // + // Type, Optional?, OptionalTag + // + _out << "array("; writeType(returnType); + _out << ", " << ((*oli)->returnIsOptional() ? "true" : "false") << ", " + << ((*oli)->returnIsOptional() ? (*oli)->returnTag() : 0) << ')'; } else { @@ -685,7 +704,7 @@ CodeVisitor::visitExceptionStart(const ExceptionPtr& p) // // Data members are represented as an array: // - // ('MemberName', MemberType) + // ('MemberName', MemberType, Optional, Tag) // // where MemberType is either a primitive type constant (T_INT, etc.) or the id of a constructed type. // @@ -696,12 +715,13 @@ CodeVisitor::visitExceptionStart(const ExceptionPtr& p) { if(dmli != members.begin()) { - _out << ',' << nl; + _out << ','; } _out.inc(); _out << nl << "array('" << fixIdent((*dmli)->name()) << "', "; writeType((*dmli)->type()); - _out << ')'; + _out << ", " << ((*dmli)->optional() ? "true" : "false") << ", " + << ((*dmli)->optional() ? (*dmli)->tag() : 0) << ')'; _out.dec(); } _out << ')'; @@ -1340,6 +1360,10 @@ CodeVisitor::writeConstructorParams(const MemberInfoList& members) { writeConstantValue(member->type(), member->defaultValueType(), member->defaultValue()); } + else if(member->optional()) + { + _out << "Ice_Unset"; + } else { writeDefaultValue(member->type()); @@ -1817,4 +1841,3 @@ main(int argc, char* argv[]) return EXIT_FAILURE; } } - diff --git a/php/allTests.py b/php/allTests.py index 6c64a6cfb09..6b8cd64291d 100755 --- a/php/allTests.py +++ b/php/allTests.py @@ -37,6 +37,7 @@ tests = [ ("Ice/slicing/exceptions", ["core"]), ("Ice/slicing/objects", ["core"]), ("Ice/defaultValue", ["core"]), + ("Ice/optional", ["core"]), ("Ice/ini", ["once"]), ("Ice/scope", ["once"]), ("Slice/keyword", ["once"]), diff --git a/php/lib/Ice.php b/php/lib/Ice.php index c146f96a503..ea718c923a6 100644 --- a/php/lib/Ice.php +++ b/php/lib/Ice.php @@ -93,6 +93,17 @@ $Ice__t_LocalObject = IcePHP_defineClass('::Ice::LocalObject', "Ice_LocalObject" $Ice__t_ObjectPrx = IcePHP_defineProxy($Ice__t_Object); $Ice__t_ObjectProxySeq = IcePHP_defineSequence('::Ice::ObjectProxySeq', $Ice__t_ObjectPrx); +class Ice_UnknownSlicedObject extends Ice_ObjectImpl +{ + public function __construct() + { + } + + public $unknownTypeId; +} + +$Ice__t_UnknownSlicedObject = IcePHP_defineClass('::Ice::UnknownSlicedObject', 'Ice_UnknownSlicedObject', false, true, $Ice__t_Object, null, null); + interface Ice_ObjectFactory { public function create($id); @@ -149,10 +160,10 @@ $Ice_Protocol_1_0 = new Ice_ProtocolVersion(1, 0); $Ice_Encoding_1_0 = new Ice_EncodingVersion(1, 0); $Ice_Encoding_1_1 = new Ice_EncodingVersion(1, 1); -IcePHP_defineOperation($Ice__t_Object, 'ice_isA', 2, 1, 0, array($IcePHP__t_string), null, $IcePHP__t_bool, null); +IcePHP_defineOperation($Ice__t_Object, 'ice_isA', 2, 1, 0, array(array($IcePHP__t_string, false, 0)), null, array($IcePHP__t_bool, false, 0), null); IcePHP_defineOperation($Ice__t_Object, 'ice_ping', 2, 1, 0, null, null, null, null); -IcePHP_defineOperation($Ice__t_Object, 'ice_id', 2, 1, 0, null, null, $IcePHP__t_string, null); -IcePHP_defineOperation($Ice__t_Object, 'ice_ids', 2, 1, 0, null, null, $Ice__t_StringSeq, null); +IcePHP_defineOperation($Ice__t_Object, 'ice_id', 2, 1, 0, null, null, array($IcePHP__t_string, false, 0), null); +IcePHP_defineOperation($Ice__t_Object, 'ice_ids', 2, 1, 0, null, null, array($Ice__t_StringSeq, false, 0), null); // // Proxy comparison functions. diff --git a/php/lib/Ice_ns.php b/php/lib/Ice_ns.php index f1229986f9d..81df7b84817 100644 --- a/php/lib/Ice_ns.php +++ b/php/lib/Ice_ns.php @@ -98,6 +98,17 @@ namespace Ice $Ice__t_ObjectPrx = IcePHP_defineProxy($Ice__t_Object); $Ice__t_ObjectProxySeq = IcePHP_defineSequence('::Ice::ObjectProxySeq', $Ice__t_ObjectPrx); + class UnknownSlicedObject extends ObjectImpl + { + public function __construct() + { + } + + public $unknownTypeId; + } + + $Ice__t_UnknownSlicedObject = IcePHP_defineClass('::Ice::UnknownSlicedObject', "\\Ice\\UnknownSlicedObject", false, true, $Ice__t_Object, null, null); + interface ObjectFactory { public function create($id); @@ -157,10 +168,10 @@ $Ice_Protocol_1_0 = new Ice\ProtocolVersion(1, 0); $Ice_Encoding_1_0 = new Ice\EncodingVersion(1, 0); $Ice_Encoding_1_1 = new Ice\EncodingVersion(1, 1); -IcePHP_defineOperation($Ice__t_Object, 'ice_isA', 2, 1, 0, array($IcePHP__t_string), array(), $IcePHP__t_bool, null); +IcePHP_defineOperation($Ice__t_Object, 'ice_isA', 2, 1, 0, array(array($IcePHP__t_string, false, 0)), null, array($IcePHP__t_bool, false, 0), null); IcePHP_defineOperation($Ice__t_Object, 'ice_ping', 2, 1, 0, null, null, null, null); -IcePHP_defineOperation($Ice__t_Object, 'ice_id', 2, 1, 0, null, null, $IcePHP__t_string, null); -IcePHP_defineOperation($Ice__t_Object, 'ice_ids', 2, 1, 0, null, null, $Ice__t_StringSeq, null); +IcePHP_defineOperation($Ice__t_Object, 'ice_id', 2, 1, 0, null, null, array($IcePHP__t_string, false, 0), null); +IcePHP_defineOperation($Ice__t_Object, 'ice_ids', 2, 1, 0, null, null, array($Ice__t_StringSeq, false, 0), null); } namespace Ice diff --git a/php/src/IcePHP/Communicator.cpp b/php/src/IcePHP/Communicator.cpp index 57e766eab31..d03801ade74 100644 --- a/php/src/IcePHP/Communicator.cpp +++ b/php/src/IcePHP/Communicator.cpp @@ -1592,7 +1592,20 @@ IcePHP::ObjectFactoryI::create(const string& id) // // Get the type information. // - ClassInfoPtr cls = getClassInfoById(id TSRMLS_CC); + ClassInfoPtr cls; + if(id == Ice::Object::ice_staticId()) + { + // + // When the ID is that of Ice::Object, it indicates that the stream has not + // found a factory and is providing us an opportunity to preserve the object. + // + cls = getClassInfoById("::Ice::UnknownSlicedObject" TSRMLS_CC); + } + else + { + cls = getClassInfoById(id TSRMLS_CC); + } + if(!cls) { return 0; @@ -1652,7 +1665,7 @@ IcePHP::ObjectFactoryI::create(const string& id) MAKE_STD_ZVAL(obj); AutoDestroy destroy(obj); - if(object_init_ex(obj, cls->zce) != SUCCESS) + if(object_init_ex(obj, const_cast<zend_class_entry*>(cls->zce)) != SUCCESS) { throw AbortMarshaling(); } diff --git a/php/src/IcePHP/Config.h b/php/src/IcePHP/Config.h index 055e732a6c2..891640b12f1 100644 --- a/php/src/IcePHP/Config.h +++ b/php/src/IcePHP/Config.h @@ -87,6 +87,7 @@ ZEND_BEGIN_MODULE_GLOBALS(ice) void* nameToClassInfoMap; void* proxyInfoMap; void* exceptionInfoMap; + zval* unset; ZEND_END_MODULE_GLOBALS(ice) #ifdef ZTS diff --git a/php/src/IcePHP/Init.cpp b/php/src/IcePHP/Init.cpp index 5f2f3f7d3a0..8e8e436df81 100644 --- a/php/src/IcePHP/Init.cpp +++ b/php/src/IcePHP/Init.cpp @@ -64,6 +64,7 @@ ZEND_END_ARG_INFO() ZEND_FE(IcePHP_defineStruct, NULL) \ ZEND_FE(IcePHP_defineSequence, NULL) \ ZEND_FE(IcePHP_defineDictionary, NULL) \ + ZEND_FE(IcePHP_declareProxy, NULL) \ ZEND_FE(IcePHP_defineProxy, NULL) \ ZEND_FE(IcePHP_declareClass, NULL) \ ZEND_FE(IcePHP_defineClass, NULL) \ @@ -149,6 +150,7 @@ int initIceGlobals(zend_ice_globals* g) g->nameToClassInfoMap = 0; g->proxyInfoMap = 0; g->exceptionInfoMap = 0; + g->unset = 0; return SUCCESS; } @@ -172,7 +174,7 @@ ZEND_MINIT_FUNCTION(ice) return FAILURE; } - if(!typesInit(TSRMLS_C)) + if(!typesInit(INIT_FUNC_ARGS_PASSTHRU)) { return FAILURE; } diff --git a/php/src/IcePHP/Makefile b/php/src/IcePHP/Makefile index 910b4e6e031..f596e15861d 100644 --- a/php/src/IcePHP/Makefile +++ b/php/src/IcePHP/Makefile @@ -29,7 +29,7 @@ SRCS = $(OBJS:.o=.cpp) include $(top_srcdir)/config/Make.rules.php -CPPFLAGS := -I. $(CPPFLAGS) $(ICE_FLAGS) $(PHP_FLAGS) +CPPFLAGS := -I. $(CPPFLAGS) $(ICE_FLAGS) $(PHP_FLAGS) -DPHP_DEBUG LINKWITH := $(ICE_LIBS) $(PHP_LIBS) $(CXXLIBS) diff --git a/php/src/IcePHP/Operation.cpp b/php/src/IcePHP/Operation.cpp index db68b52ee24..bb8c1e3cebb 100644 --- a/php/src/IcePHP/Operation.cpp +++ b/php/src/IcePHP/Operation.cpp @@ -26,6 +26,18 @@ ZEND_FUNCTION(IcePHP_Operation_call); namespace IcePHP { +class ParamInfo : public IceUtil::Shared +{ +public: + + TypeInfoPtr type; + bool optional; + int tag; + int pos; +}; +typedef IceUtil::Handle<ParamInfo> ParamInfoPtr; +typedef list<ParamInfoPtr> ParamInfoList; + // // Receives an out parameter or return value. // @@ -38,6 +50,8 @@ public: virtual void unmarshaled(zval*, zval*, void* TSRMLS_DC); + void unset(TSRMLS_D); + zval* zv; }; typedef IceUtil::Handle<ResultCallback> ResultCallbackPtr; @@ -60,20 +74,21 @@ public: Ice::OperationMode mode; Ice::OperationMode sendMode; Ice::FormatType format; - TypeInfoList inParams; - TypeInfoList outParams; - TypeInfoPtr returnType; + ParamInfoList inParams; + ParamInfoList optionalInParams; + ParamInfoList outParams; + ParamInfoList optionalOutParams; + ParamInfoPtr returnType; ExceptionInfoList exceptions; - bool sendsClasses; - bool returnsClasses; int numParams; private: zend_internal_function* _zendFunction; - static void convertParams(zval*, TypeInfoList&, bool& TSRMLS_DC); - static void getArgInfo(zend_arg_info&, const TypeInfoPtr&, bool); + static void convertParams(zval*, ParamInfoList& TSRMLS_DC); + static ParamInfoPtr convertParam(zval*, int TSRMLS_DC); + static void getArgInfo(zend_arg_info&, const ParamInfoPtr&, bool); }; typedef IceUtil::Handle<OperationI> OperationIPtr; @@ -188,19 +203,26 @@ IcePHP::ResultCallback::unmarshaled(zval* val, zval*, void* TSRMLS_DC) Z_ADDREF_P(zv); } +void +IcePHP::ResultCallback::unset(TSRMLS_D) +{ + MAKE_STD_ZVAL(zv); + IcePHP::unset(zv TSRMLS_DC); +} + // // OperationI implementation. // IcePHP::OperationI::OperationI(const char* n, Ice::OperationMode m, Ice::OperationMode sm, Ice::FormatType f, zval* in, zval* out, zval* ret, zval* ex TSRMLS_DC) : - name(n), mode(m), sendMode(sm), format(f), sendsClasses(false), returnsClasses(false), _zendFunction(0) + name(n), mode(m), sendMode(sm), format(f), _zendFunction(0) { // // inParams // if(in) { - convertParams(in, inParams, sendsClasses TSRMLS_CC); + convertParams(in, inParams TSRMLS_CC); } // @@ -208,22 +230,53 @@ IcePHP::OperationI::OperationI(const char* n, Ice::OperationMode m, Ice::Operati // if(out) { - convertParams(out, outParams, returnsClasses TSRMLS_CC); + convertParams(out, outParams TSRMLS_CC); } - numParams = static_cast<int>(inParams.size() + outParams.size()); - // // returnType // if(ret) { - returnType = Wrapper<TypeInfoPtr>::value(ret TSRMLS_CC); - if(!returnsClasses) + returnType = convertParam(ret, 0 TSRMLS_CC); + } + + numParams = static_cast<int>(inParams.size() + outParams.size()); + + class SortFn + { + public: + static bool compare(const ParamInfoPtr& lhs, const ParamInfoPtr& rhs) { - returnsClasses = returnType->usesClasses(); + return lhs->tag < rhs->tag; } + + static bool isRequired(const ParamInfoPtr& i) + { + return !i->optional; + } + }; + + // + // The inParams list represents the parameters in the order of declaration. + // We also need a sorted list of optional parameters. + // + ParamInfoList l = inParams; + copy(l.begin(), remove_if(l.begin(), l.end(), SortFn::isRequired), back_inserter(optionalInParams)); + optionalInParams.sort(SortFn::compare); + + // + // The outParams list represents the parameters in the order of declaration. + // We also need a sorted list of optional parameters. If the return value is + // optional, we must include it in this list. + // + l = outParams; + copy(l.begin(), remove_if(l.begin(), l.end(), SortFn::isRequired), back_inserter(optionalOutParams)); + if(returnType && returnType->optional) + { + optionalOutParams.push_back(returnType); } + optionalOutParams.sort(SortFn::compare); // // exceptions @@ -265,7 +318,7 @@ IcePHP::OperationI::function() zend_arg_info* argInfo = new zend_arg_info[numParams]; int i = 0; - TypeInfoList::const_iterator p; + ParamInfoList::const_iterator p; for(p = inParams.begin(); p != inParams.end(); ++p, ++i) { getArgInfo(argInfo[i], *p, false); @@ -302,43 +355,73 @@ IcePHP::OperationI::function() } void -IcePHP::OperationI::convertParams(zval* p, TypeInfoList& params, bool& usesClasses TSRMLS_DC) +IcePHP::OperationI::convertParams(zval* p, ParamInfoList& params TSRMLS_DC) { - usesClasses = false; - assert(Z_TYPE_P(p) == IS_ARRAY); HashTable* arr = Z_ARRVAL_P(p); HashPosition pos; zend_hash_internal_pointer_reset_ex(arr, &pos); void* data; + int i = 0; while(zend_hash_get_current_data_ex(arr, &data, &pos) != FAILURE) { zval** val = reinterpret_cast<zval**>(data); - TypeInfoPtr type = Wrapper<TypeInfoPtr>::value(*val TSRMLS_CC); - params.push_back(type); - if(!usesClasses) - { - usesClasses = type->usesClasses(); - } + params.push_back(convertParam(*val, i TSRMLS_CC)); zend_hash_move_forward_ex(arr, &pos); + ++i; } } +ParamInfoPtr +IcePHP::OperationI::convertParam(zval* p, int pos TSRMLS_DC) +{ + assert(Z_TYPE_P(p) == IS_ARRAY); + HashTable* arr = Z_ARRVAL_P(p); + assert(zend_hash_num_elements(arr) == 3); + + ParamInfoPtr param = new ParamInfo; + zval** m; + + zend_hash_index_find(arr, 0, reinterpret_cast<void**>(&m)); + param->type = Wrapper<TypeInfoPtr>::value(*m TSRMLS_CC); + zend_hash_index_find(arr, 1, reinterpret_cast<void**>(&m)); + assert(Z_TYPE_PP(m) == IS_BOOL); + param->optional = Z_BVAL_PP(m) ? true : false; + zend_hash_index_find(arr, 2, reinterpret_cast<void**>(&m)); + assert(Z_TYPE_PP(m) == IS_LONG); + param->tag = Z_LVAL_PP(m); + param->pos = pos; + + return param; +} + void -IcePHP::OperationI::getArgInfo(zend_arg_info& arg, const TypeInfoPtr& info, bool out) +IcePHP::OperationI::getArgInfo(zend_arg_info& arg, const ParamInfoPtr& info, bool out) { arg.name = 0; arg.class_name = 0; arg.allow_null = 1; - const bool isArray = SequenceInfoPtr::dynamicCast(info) || DictionaryInfoPtr::dynamicCast(info); + if(!info->optional) + { + const bool isArray = SequenceInfoPtr::dynamicCast(info->type) || DictionaryInfoPtr::dynamicCast(info->type); #if PHP_VERSION_ID < 50400 - arg.array_type_hint = isArray ? 1 : 0; - arg.return_reference = 0; + arg.array_type_hint = isArray ? 1 : 0; + arg.return_reference = 0; +#else + arg.type_hint = isArray ? IS_ARRAY : 0; +#endif + } + else + { +#if PHP_VERSION_ID < 50400 + arg.array_type_hint = 0; + arg.return_reference = 0; #else - arg.type_hint = isArray ? IS_ARRAY : 0; + arg.type_hint = 0; #endif + } arg.pass_by_reference = out ? 1 : 0; } @@ -395,16 +478,47 @@ IcePHP::TypedInvocation::prepareRequest(int argc, zval** args, Ice::ByteSeq& byt os->startEncapsulation(_prx->ice_getEncodingVersion(), _op->format); ObjectMap objectMap; - int i = 0; - for(TypeInfoList::iterator p = _op->inParams.begin(); p != _op->inParams.end(); ++p, ++i) + ParamInfoList::iterator p; + + // + // Validate the supplied arguments. + // + for(p = _op->inParams.begin(); p != _op->inParams.end(); ++p) { - zval* arg = args[i]; - if(!(*p)->validate(arg TSRMLS_CC)) + ParamInfoPtr info = *p; + zval* arg = args[info->pos]; + if((!info->optional || !isUnset(arg TSRMLS_CC)) && !info->type->validate(arg TSRMLS_CC)) { - invalidArgument("invalid value for argument %d in operation `%s'" TSRMLS_CC, i, _op->name.c_str()); + invalidArgument("invalid value for argument %d in operation `%s'" TSRMLS_CC, info->pos + 1, + _op->name.c_str()); return false; } - (*p)->marshal(arg, os, &objectMap TSRMLS_CC); + } + + // + // Marshal the required parameters. + // + for(p = _op->inParams.begin(); p != _op->inParams.end(); ++p) + { + ParamInfoPtr info = *p; + if(!info->optional) + { + zval* arg = args[info->pos]; + info->type->marshal(arg, os, &objectMap, false TSRMLS_CC); + } + } + + // + // Marshal the optional parameters. + // + for(p = _op->optionalInParams.begin(); p != _op->optionalInParams.end(); ++p) + { + ParamInfoPtr info = *p; + zval* arg = args[info->pos]; + if(!isUnset(arg TSRMLS_CC) && os->writeOptional(info->tag, info->type->optionalFormat())) + { + info->type->marshal(arg, os, &objectMap, true TSRMLS_CC); + } } os->endEncapsulation(); @@ -440,6 +554,8 @@ IcePHP::TypedInvocation::unmarshalResults(int argc, zval** args, zval* ret, is->startEncapsulation(); + ParamInfoList::iterator p; + // // These callbacks collect references to the unmarshaled values. We copy them into // the argument list *after* any pending objects have been unmarshaled. @@ -447,23 +563,56 @@ IcePHP::TypedInvocation::unmarshalResults(int argc, zval** args, zval* ret, ResultCallbackList outParamCallbacks; ResultCallbackPtr retCallback; + outParamCallbacks.resize(_op->outParams.size()); + // - // Unmarshal the out parameters. + // Unmarshal the required out parameters. // - for(TypeInfoList::iterator p = _op->outParams.begin(); p != _op->outParams.end(); ++p) + for(p = _op->outParams.begin(); p != _op->outParams.end(); ++p) { - ResultCallbackPtr cb = new ResultCallback; - outParamCallbacks.push_back(cb); - (*p)->unmarshal(is, cb, _communicator, 0, 0 TSRMLS_CC); + ParamInfoPtr info = *p; + if(!info->optional) + { + ResultCallbackPtr cb = new ResultCallback; + outParamCallbacks[info->pos] = cb; + info->type->unmarshal(is, cb, _communicator, 0, 0, false TSRMLS_CC); + } } // - // Unmarshal the return value. + // Unmarshal the required return value, if any. // - if(_op->returnType) + if(_op->returnType && !_op->returnType->optional) { retCallback = new ResultCallback; - _op->returnType->unmarshal(is, retCallback, _communicator, 0, 0 TSRMLS_CC); + _op->returnType->type->unmarshal(is, retCallback, _communicator, 0, 0, false TSRMLS_CC); + } + + // + // Unmarshal the optional results. This includes an optional return value. + // + for(p = _op->optionalOutParams.begin(); p != _op->optionalOutParams.end(); ++p) + { + ParamInfoPtr info = *p; + + ResultCallbackPtr cb = new ResultCallback; + if(info->tag == _op->returnType->tag) + { + retCallback = cb; + } + else + { + outParamCallbacks[info->pos] = cb; + } + + if(is->readOptional(info->tag, info->type->optionalFormat())) + { + info->type->unmarshal(is, cb, _communicator, 0, 0, true TSRMLS_CC); + } + else + { + cb->unset(TSRMLS_C); + } } is->endEncapsulation(); @@ -695,7 +844,7 @@ ZEND_FUNCTION(IcePHP_defineOperation) zval* returnType; zval* exceptions; - if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("osllla!a!o!a!"), &cls, &name, &nameLen, + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("osllla!a!a!a!"), &cls, &name, &nameLen, &mode, &sendMode, &format, &inParams, &outParams, &returnType, &exceptions) == FAILURE) { return; diff --git a/php/src/IcePHP/Types.cpp b/php/src/IcePHP/Types.cpp index 7a3892feba8..4e34f204ce2 100644 --- a/php/src/IcePHP/Types.cpp +++ b/php/src/IcePHP/Types.cpp @@ -35,6 +35,8 @@ zend_class_entry* exceptionInfoClassEntry = 0; static zend_object_handlers _typeInfoHandlers; static zend_object_handlers _exceptionInfoHandlers; +static string _unsetGUID = "710A52F2-A014-4CB2-AF40-348D48DBCDDD"; + extern "C" { static zend_object_value handleTypeInfoAlloc(zend_class_entry* TSRMLS_DC); @@ -49,6 +51,25 @@ typedef map<string, ClassInfoPtr> ClassInfoMap; typedef map<string, ExceptionInfoPtr> ExceptionInfoMap; // +// addProxyInfo() +// +static void +addProxyInfo(const ProxyInfoPtr& p TSRMLS_DC) +{ + ProxyInfoMap* m; + if(ICE_G(proxyInfoMap)) + { + m = reinterpret_cast<ProxyInfoMap*>(ICE_G(proxyInfoMap)); + } + else + { + m = new ProxyInfoMap; + ICE_G(proxyInfoMap) = m; + } + m->insert(ProxyInfoMap::value_type(p->id, p)); +} + +// // getProxyInfo() // static IcePHP::ProxyInfoPtr @@ -444,12 +465,17 @@ IcePHP::SlicedDataUtil::getMember(zval* obj, ObjectMap* objectMap TSRMLS_DC) if(Z_TYPE_P(sd) != IS_NULL) { +#ifndef NDEBUG int status; +#endif // // The "slices" member is an array of Ice_SliceInfo objects. // - status = zend_hash_find(Z_OBJPROP_P(sd), STRCAST("slices"), sizeof("slices"), &data); +#ifndef NDEBUG + status = +#endif + zend_hash_find(Z_OBJPROP_P(sd), STRCAST("slices"), sizeof("slices"), &data); assert(status == SUCCESS); zval* sl = *(reinterpret_cast<zval**>(data)); assert(Z_TYPE_P(sl) == IS_ARRAY); @@ -468,13 +494,19 @@ IcePHP::SlicedDataUtil::getMember(zval* obj, ObjectMap* objectMap TSRMLS_DC) Ice::SliceInfoPtr info = new Ice::SliceInfo; - status = zend_hash_find(Z_OBJPROP_P(s), STRCAST("typeId"), sizeof("typeId"), &data); +#ifndef NDEBUG + status = +#endif + zend_hash_find(Z_OBJPROP_P(s), STRCAST("typeId"), sizeof("typeId"), &data); assert(status == SUCCESS); zval* typeId = *(reinterpret_cast<zval**>(data)); assert(Z_TYPE_P(typeId) == IS_STRING); info->typeId = string(Z_STRVAL_P(typeId), Z_STRLEN_P(typeId)); - status = zend_hash_find(Z_OBJPROP_P(s), STRCAST("bytes"), sizeof("bytes"), &data); +#ifndef NDEBUG + status = +#endif + zend_hash_find(Z_OBJPROP_P(s), STRCAST("bytes"), sizeof("bytes"), &data); assert(status == SUCCESS); zval* bytes = *(reinterpret_cast<zval**>(data)); assert(Z_TYPE_P(bytes) == IS_ARRAY); @@ -493,7 +525,10 @@ IcePHP::SlicedDataUtil::getMember(zval* obj, ObjectMap* objectMap TSRMLS_DC) zend_hash_move_forward_ex(barr, &bpos); } - status = zend_hash_find(Z_OBJPROP_P(s), STRCAST("objects"), sizeof("objects"), &data); +#ifndef NDEBUG + status = +#endif + zend_hash_find(Z_OBJPROP_P(s), STRCAST("objects"), sizeof("objects"), &data); assert(status == SUCCESS); zval* objects = *(reinterpret_cast<zval**>(data)); assert(Z_TYPE_P(objects) == IS_ARRAY); @@ -548,12 +583,6 @@ IcePHP::TypeInfo::TypeInfo() { } -bool -IcePHP::TypeInfo::usesClasses() -{ - return false; -} - void IcePHP::TypeInfo::unmarshaled(zval*, zval*, void* TSRMLS_DC) { @@ -720,8 +749,65 @@ IcePHP::PrimitiveInfo::validate(zval* zv TSRMLS_DC) return true; } +bool +IcePHP::PrimitiveInfo::variableLength() const +{ + return kind == KindString; +} + +int +IcePHP::PrimitiveInfo::wireSize() const +{ + switch(kind) + { + case KindBool: + case KindByte: + return 1; + case KindShort: + return 2; + case KindInt: + return 4; + case KindLong: + return 8; + case KindFloat: + return 4; + case KindDouble: + return 8; + case KindString: + return 1; + } + assert(false); + return 0; +} + +Ice::OptionalFormat +IcePHP::PrimitiveInfo::optionalFormat() const +{ + switch(kind) + { + case KindBool: + case KindByte: + return Ice::OptionalFormatF1; + case KindShort: + return Ice::OptionalFormatF2; + case KindInt: + return Ice::OptionalFormatF4; + case KindLong: + return Ice::OptionalFormatF8; + case KindFloat: + return Ice::OptionalFormatF4; + case KindDouble: + return Ice::OptionalFormatF8; + case KindString: + return Ice::OptionalFormatVSize; + } + + assert(false); + return Ice::OptionalFormatF1; +} + void -IcePHP::PrimitiveInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* TSRMLS_DC) +IcePHP::PrimitiveInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap*, bool TSRMLS_DC) { switch(kind) { @@ -830,7 +916,7 @@ IcePHP::PrimitiveInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectM void IcePHP::PrimitiveInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, - const CommunicatorInfoPtr&, zval* target, void* closure TSRMLS_DC) + const CommunicatorInfoPtr&, zval* target, void* closure, bool TSRMLS_DC) { zval* zv; MAKE_STD_ZVAL(zv); @@ -931,6 +1017,22 @@ IcePHP::PrimitiveInfo::print(zval* zv, IceUtilInternal::Output& out, PrintObject // // EnumInfo implementation. // +IcePHP::EnumInfo::EnumInfo(const string& ident, zval* en TSRMLS_DC) : + id(ident) +{ + HashTable* arr = Z_ARRVAL_P(en); + 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); + assert(Z_TYPE_PP(val) == IS_STRING); + const_cast<Ice::StringSeq&>(enumerators).push_back(Z_STRVAL_PP(val)); + zend_hash_move_forward_ex(arr, &pos); + } +} + string IcePHP::EnumInfo::getId() const { @@ -948,54 +1050,45 @@ IcePHP::EnumInfo::validate(zval* zv TSRMLS_DC) return false; } +bool +IcePHP::EnumInfo::variableLength() const +{ + return true; +} + +int +IcePHP::EnumInfo::wireSize() const +{ + return 1; +} + +Ice::OptionalFormat +IcePHP::EnumInfo::optionalFormat() const +{ + return Ice::OptionalFormatSize; +} + void -IcePHP::EnumInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* TSRMLS_DC) +IcePHP::EnumInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap*, bool TSRMLS_DC) { assert(Z_TYPE_P(zv) == IS_LONG); // validate() should have caught this. Ice::Int val = static_cast<Ice::Int>(Z_LVAL_P(zv)); - Ice::Int count = static_cast<Ice::Int>(enumerators.size()); + const Ice::Int count = static_cast<Ice::Int>(enumerators.size()); assert(val >= 0 && val < count); // validate() should have caught this. - if(count <= 127) - { - os->write(static_cast<Ice::Byte>(val)); - } - else if(count <= 32767) - { - os->write(static_cast<Ice::Short>(val)); - } - else - { - os->write(val); - } + os->writeEnum(val, count); } void IcePHP::EnumInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, - const CommunicatorInfoPtr&, zval* target, void* closure TSRMLS_DC) + const CommunicatorInfoPtr&, zval* target, void* closure, bool TSRMLS_DC) { zval* zv; ALLOC_INIT_ZVAL(zv); AutoDestroy destroy(zv); - Ice::Int val; - Ice::Int count = static_cast<Ice::Int>(enumerators.size()); - if(count <= 127) - { - Ice::Byte b; - is->read(b); - val = b; - } - else if(count <= 32767) - { - Ice::Short sh; - is->read(sh); - val = sh; - } - else - { - is->read(val); - } + const Ice::Int count = static_cast<Ice::Int>(enumerators.size()); + Ice::Int val = is->readEnum(count); if(val < 0 || val >= count) { @@ -1025,6 +1118,12 @@ IcePHP::EnumInfo::print(zval* zv, IceUtilInternal::Output& out, PrintObjectHisto void IcePHP::DataMember::unmarshaled(zval* zv, zval* target, void* TSRMLS_DC) { + setMember(target, zv TSRMLS_CC); +} + +void +IcePHP::DataMember::setMember(zval* target, zval* zv TSRMLS_DC) +{ assert(Z_TYPE_P(target) == IS_OBJECT); // @@ -1049,9 +1148,100 @@ IcePHP::DataMember::unmarshaled(zval* zv, zval* target, void* TSRMLS_DC) } } +static void +convertDataMembers(zval* zv, DataMemberList& reqMembers, DataMemberList& optMembers, bool allowOptional TSRMLS_DC) +{ + list<DataMemberPtr> optList; + + assert(Z_TYPE_P(zv) == IS_ARRAY); + HashTable* membersArray = Z_ARRVAL_P(zv); + void* data; + HashPosition pos; + zend_hash_internal_pointer_reset_ex(membersArray, &pos); + while(zend_hash_get_current_data_ex(membersArray, &data, &pos) != FAILURE) + { + zval** arr = reinterpret_cast<zval**>(data); + + DataMemberPtr m = new DataMember(); + zval** elem; + + assert(Z_TYPE_PP(arr) == IS_ARRAY); + HashTable* member = Z_ARRVAL_PP(arr); + assert(zend_hash_num_elements(member) == allowOptional ? 4 : 2); + zend_hash_index_find(member, 0, reinterpret_cast<void**>(&elem)); + assert(Z_TYPE_PP(elem) == IS_STRING); + m->name = Z_STRVAL_PP(elem); + zend_hash_index_find(member, 1, reinterpret_cast<void**>(&elem)); + assert(Z_TYPE_PP(elem) == IS_OBJECT); + m->type = Wrapper<TypeInfoPtr>::value(*elem TSRMLS_CC); + + if(allowOptional) + { + zend_hash_index_find(member, 2, reinterpret_cast<void**>(&elem)); + assert(Z_TYPE_PP(elem) == IS_BOOL); + m->optional = Z_BVAL_PP(elem) ? true : false; + zend_hash_index_find(member, 3, reinterpret_cast<void**>(&elem)); + assert(Z_TYPE_PP(elem) == IS_LONG); + m->tag = static_cast<int>(Z_LVAL_PP(elem)); + } + else + { + m->optional = false; + m->tag = 0; + } + + if(m->optional) + { + optList.push_back(m); + } + else + { + reqMembers.push_back(m); + } + + zend_hash_move_forward_ex(membersArray, &pos); + } + + if(allowOptional) + { + class SortFn + { + public: + static bool compare(const DataMemberPtr& lhs, const DataMemberPtr& rhs) + { + return lhs->tag < rhs->tag; + } + }; + + optList.sort(SortFn::compare); + copy(optList.begin(), optList.end(), back_inserter(optMembers)); + } +} + // // StructInfo implementation. // +IcePHP::StructInfo::StructInfo(const string& ident, const string& n, zval* m TSRMLS_DC) : + id(ident), name(n) +{ + DataMemberList opt; + convertDataMembers(m, const_cast<DataMemberList&>(members), opt, false TSRMLS_CC); + assert(opt.empty()); + const_cast<zend_class_entry*&>(zce) = nameToClass(name TSRMLS_CC); + assert(zce); + + _variableLength = false; + _wireSize = 0; + for(DataMemberList::const_iterator p = members.begin(); p != members.end(); ++p) + { + if(!_variableLength && (*p)->type->variableLength()) + { + _variableLength = true; + } + _wireSize += (*p)->type->wireSize(); + } +} + string IcePHP::StructInfo::getId() const { @@ -1082,26 +1272,42 @@ IcePHP::StructInfo::validate(zval* zv TSRMLS_DC) } bool -IcePHP::StructInfo::usesClasses() +IcePHP::StructInfo::variableLength() const { - for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q) - { - if((*q)->type->usesClasses()) - { - return true; - } - } + return _variableLength; +} - return false; +int +IcePHP::StructInfo::wireSize() const +{ + return _wireSize; +} + +Ice::OptionalFormat +IcePHP::StructInfo::optionalFormat() const +{ + return _variableLength ? Ice::OptionalFormatFSize : Ice::OptionalFormatVSize; } void -IcePHP::StructInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* objectMap TSRMLS_DC) +IcePHP::StructInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* objectMap, bool optional TSRMLS_DC) { assert(Z_TYPE_P(zv) == IS_OBJECT); // validate() should have caught this. assert(Z_OBJCE_P(zv) == zce); // validate() should have caught this. - for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q) + if(optional) + { + if(_variableLength) + { + os->startSize(); + } + else + { + os->writeSize(_wireSize); + } + } + + for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) { DataMemberPtr member = *q; @@ -1118,28 +1324,46 @@ IcePHP::StructInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* invalidArgument("invalid value for %s member `%s'" TSRMLS_CC, id.c_str(), member->name.c_str()); throw AbortMarshaling(); } - member->type->marshal(*val, os, objectMap TSRMLS_CC); + + member->type->marshal(*val, os, objectMap, false TSRMLS_CC); + } + + if(optional && _variableLength) + { + os->endSize(); } } void IcePHP::StructInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, - const CommunicatorInfoPtr& comm, zval* target, void* closure TSRMLS_DC) + const CommunicatorInfoPtr& comm, zval* target, void* closure, bool optional TSRMLS_DC) { zval* zv; MAKE_STD_ZVAL(zv); AutoDestroy destroy(zv); - if(object_init_ex(zv, zce) != SUCCESS) + if(object_init_ex(zv, const_cast<zend_class_entry*>(zce)) != SUCCESS) { runtimeError("unable to initialize object of type %s" TSRMLS_CC, zce->name); throw AbortMarshaling(); } - for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q) + if(optional) + { + if(_variableLength) + { + is->skip(4); + } + else + { + is->skipSize(); + } + } + + for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) { DataMemberPtr member = *q; - member->type->unmarshal(is, member, comm, zv, 0 TSRMLS_CC); + member->type->unmarshal(is, member, comm, zv, 0, false TSRMLS_CC); } cb->unmarshaled(zv, target, closure TSRMLS_CC); @@ -1154,7 +1378,7 @@ IcePHP::StructInfo::print(zval* zv, IceUtilInternal::Output& out, PrintObjectHis return; } out.sb(); - for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q) + for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) { DataMemberPtr member = *q; @@ -1176,16 +1400,22 @@ IcePHP::StructInfo::print(zval* zv, IceUtilInternal::Output& out, PrintObjectHis void IcePHP::StructInfo::destroy() { - for(DataMemberList::iterator p = members.begin(); p != members.end(); ++p) + for(DataMemberList::const_iterator p = members.begin(); p != members.end(); ++p) { (*p)->type->destroy(); } - members.clear(); + const_cast<DataMemberList&>(members).clear(); } // // SequenceInfo implementation. // +IcePHP::SequenceInfo::SequenceInfo(const string& ident, zval* e TSRMLS_DC) : + id(ident) +{ + const_cast<TypeInfoPtr&>(elementType) = Wrapper<TypeInfoPtr>::value(e TSRMLS_CC); +} + string IcePHP::SequenceInfo::getId() const { @@ -1199,62 +1429,102 @@ IcePHP::SequenceInfo::validate(zval* zv TSRMLS_DC) } bool -IcePHP::SequenceInfo::usesClasses() +IcePHP::SequenceInfo::variableLength() const { - return elementType->usesClasses(); + return true; +} + +int +IcePHP::SequenceInfo::wireSize() const +{ + return 1; +} + +Ice::OptionalFormat +IcePHP::SequenceInfo::optionalFormat() const +{ + return elementType->variableLength() ? Ice::OptionalFormatFSize : Ice::OptionalFormatVSize; } void -IcePHP::SequenceInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* objectMap TSRMLS_DC) +IcePHP::SequenceInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* objectMap, bool optional TSRMLS_DC) { - if(Z_TYPE_P(zv) == IS_NULL) + Ice::Int sz = 0; + HashTable* arr = 0; + + if(Z_TYPE_P(zv) != IS_NULL) { - os->writeSize(0); - return; + assert(Z_TYPE_P(zv) == IS_ARRAY); // validate() should have caught this. + arr = Z_ARRVAL_P(zv); + sz = static_cast<Ice::Int>(zend_hash_num_elements(arr)); } - assert(Z_TYPE_P(zv) == IS_ARRAY); // validate() should have caught this. - - HashTable* arr = Z_ARRVAL_P(zv); - - Ice::Int sz = static_cast<Ice::Int>(zend_hash_num_elements(arr)); + if(optional) + { + if(elementType->variableLength()) + { + os->startSize(); + } + else if(elementType->wireSize() > 1) + { + os->writeSize(sz == 0 ? 1 : sz * elementType->wireSize() + (sz > 254 ? 5 : 1)); + } + } if(sz == 0) { os->writeSize(0); - return; } - - PrimitiveInfoPtr pi = PrimitiveInfoPtr::dynamicCast(elementType); - if(pi) + else { - marshalPrimitiveSequence(pi, zv, os TSRMLS_CC); - return; - } + PrimitiveInfoPtr pi = PrimitiveInfoPtr::dynamicCast(elementType); + if(pi) + { + marshalPrimitiveSequence(pi, zv, os TSRMLS_CC); + return; + } - HashPosition pos; - zend_hash_internal_pointer_reset_ex(arr, &pos); + HashPosition pos; + zend_hash_internal_pointer_reset_ex(arr, &pos); - os->writeSize(sz); + os->writeSize(sz); - void* data; - while(zend_hash_get_current_data_ex(arr, &data, &pos) != FAILURE) - { - zval** val = reinterpret_cast<zval**>(data); - if(!elementType->validate(*val TSRMLS_CC)) + void* data; + while(zend_hash_get_current_data_ex(arr, &data, &pos) != FAILURE) { - invalidArgument("invalid value for sequence element `%s'" TSRMLS_CC, id.c_str()); - throw AbortMarshaling(); + zval** val = reinterpret_cast<zval**>(data); + if(!elementType->validate(*val TSRMLS_CC)) + { + invalidArgument("invalid value for sequence element `%s'" TSRMLS_CC, id.c_str()); + throw AbortMarshaling(); + } + elementType->marshal(*val, os, objectMap, false TSRMLS_CC); + zend_hash_move_forward_ex(arr, &pos); } - elementType->marshal(*val, os, objectMap TSRMLS_CC); - zend_hash_move_forward_ex(arr, &pos); + } + + if(optional && elementType->variableLength()) + { + os->endSize(); } } void IcePHP::SequenceInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, - const CommunicatorInfoPtr& comm, zval* target, void* closure TSRMLS_DC) + const CommunicatorInfoPtr& comm, zval* target, void* closure, bool optional TSRMLS_DC) { + if(optional) + { + if(elementType->variableLength()) + { + is->skip(4); + } + else if(elementType->wireSize() > 1) + { + is->skipSize(); + } + } + PrimitiveInfoPtr pi = PrimitiveInfoPtr::dynamicCast(elementType); if(pi) { @@ -1271,7 +1541,7 @@ IcePHP::SequenceInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCa for(Ice::Int i = 0; i < sz; ++i) { void* cl = reinterpret_cast<void*>(i); - elementType->unmarshal(is, this, comm, zv, cl TSRMLS_CC); + elementType->unmarshal(is, this, comm, zv, cl, false TSRMLS_CC); } cb->unmarshaled(zv, target, closure TSRMLS_CC); @@ -1331,7 +1601,7 @@ IcePHP::SequenceInfo::destroy() if(elementType) { elementType->destroy(); - elementType = 0; + const_cast<TypeInfoPtr&>(elementType) = 0; } } @@ -1689,6 +1959,16 @@ IcePHP::SequenceInfo::unmarshalPrimitiveSequence(const PrimitiveInfoPtr& pi, con // // DictionaryInfo implementation. // +IcePHP::DictionaryInfo::DictionaryInfo(const string& ident, zval* k, zval* v TSRMLS_DC) : + id(ident) +{ + const_cast<TypeInfoPtr&>(keyType) = Wrapper<TypeInfoPtr>::value(k TSRMLS_CC); + const_cast<TypeInfoPtr&>(valueType) = Wrapper<TypeInfoPtr>::value(v TSRMLS_CC); + + _variableLength = keyType->variableLength() || valueType->variableLength(); + _wireSize = keyType->wireSize() + valueType->wireSize(); +} + string IcePHP::DictionaryInfo::getId() const { @@ -1702,21 +1982,47 @@ IcePHP::DictionaryInfo::validate(zval* zv TSRMLS_DC) } bool -IcePHP::DictionaryInfo::usesClasses() +IcePHP::DictionaryInfo::variableLength() const +{ + return true; +} + +int +IcePHP::DictionaryInfo::wireSize() const +{ + return 1; +} + +Ice::OptionalFormat +IcePHP::DictionaryInfo::optionalFormat() const { - return valueType->usesClasses(); + return _variableLength ? Ice::OptionalFormatFSize : Ice::OptionalFormatVSize; } void -IcePHP::DictionaryInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* objectMap TSRMLS_DC) +IcePHP::DictionaryInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* objectMap, bool optional TSRMLS_DC) { - if(Z_TYPE_P(zv) == IS_NULL) + Ice::Int sz = 0; + HashTable* arr = 0; + + if(Z_TYPE_P(zv) != IS_NULL) { - os->writeSize(0); - return; + assert(Z_TYPE_P(zv) == IS_ARRAY); // validate() should have caught this. + arr = Z_ARRVAL_P(zv); + sz = static_cast<Ice::Int>(zend_hash_num_elements(arr)); } - assert(Z_TYPE_P(zv) == IS_ARRAY); // validate() should have caught this. + if(optional) + { + if(_variableLength) + { + os->startSize(); + } + else + { + os->writeSize(sz == 0 ? 1 : sz * _wireSize + (sz > 254 ? 5 : 1)); + } + } PrimitiveInfoPtr piKey = PrimitiveInfoPtr::dynamicCast(keyType); EnumInfoPtr enKey = EnumInfoPtr::dynamicCast(keyType); @@ -1726,123 +2032,135 @@ IcePHP::DictionaryInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, Object throw AbortMarshaling(); } - HashTable* arr = Z_ARRVAL_P(zv); - - Ice::Int sz = static_cast<Ice::Int>(zend_hash_num_elements(arr)); os->writeSize(sz); - if(sz == 0) + if(sz > 0) { - return; - } - - HashPosition pos; - void* data; - - 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); + HashPosition pos; + void* data; - // - // Get the key (which can be a long or a string). - // - char* keyStr; - uint keyLen; - ulong keyNum; - int hashKeyType = zend_hash_get_current_key_ex(arr, &keyStr, &keyLen, &keyNum, 0, &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); - // - // Store the key in a zval so that we can reuse the marshaling logic. - // - zval* zkey; - MAKE_STD_ZVAL(zkey); - AutoDestroy destroy(zkey); + // + // Get the key (which can be a long or a string). + // + char* keyStr; + uint keyLen; + ulong keyNum; + int hashKeyType = zend_hash_get_current_key_ex(arr, &keyStr, &keyLen, &keyNum, 0, &pos); - if(hashKeyType == HASH_KEY_IS_LONG) - { - ZVAL_LONG(zkey, keyNum); - } - else - { - ZVAL_STRINGL(zkey, keyStr, keyLen - 1, 1); - } + // + // Store the key in a zval so that we can reuse the marshaling logic. + // + zval* zkey; + MAKE_STD_ZVAL(zkey); + AutoDestroy destroy(zkey); - // - // Convert the zval to the required type, if necessary. - // - if(piKey) - { - switch(piKey->kind) + if(hashKeyType == HASH_KEY_IS_LONG) { - case PrimitiveInfo::KindBool: + ZVAL_LONG(zkey, keyNum); + } + else { - convert_to_boolean(zkey); - break; + ZVAL_STRINGL(zkey, keyStr, keyLen - 1, 1); } - case PrimitiveInfo::KindByte: - case PrimitiveInfo::KindShort: - case PrimitiveInfo::KindInt: - case PrimitiveInfo::KindLong: + // + // Convert the zval to the required type, if necessary. + // + if(piKey) { - if(hashKeyType == HASH_KEY_IS_STRING) + switch(piKey->kind) { - convert_to_long(zkey); + case PrimitiveInfo::KindBool: + { + convert_to_boolean(zkey); + break; } - break; - } - case PrimitiveInfo::KindString: + case PrimitiveInfo::KindByte: + case PrimitiveInfo::KindShort: + case PrimitiveInfo::KindInt: + case PrimitiveInfo::KindLong: + { + if(hashKeyType == HASH_KEY_IS_STRING) + { + convert_to_long(zkey); + } + break; + } + + case PrimitiveInfo::KindString: + { + if(hashKeyType == HASH_KEY_IS_LONG) + { + convert_to_string(zkey); + } + break; + } + + case PrimitiveInfo::KindFloat: + case PrimitiveInfo::KindDouble: + assert(false); + } + } + else { - if(hashKeyType == HASH_KEY_IS_LONG) + if(hashKeyType == HASH_KEY_IS_STRING) { - convert_to_string(zkey); + convert_to_long(zkey); } - break; } - case PrimitiveInfo::KindFloat: - case PrimitiveInfo::KindDouble: - assert(false); - } - } - else - { - if(hashKeyType == HASH_KEY_IS_STRING) + // + // Marshal the key. + // + if(!keyType->validate(zkey TSRMLS_CC)) { - convert_to_long(zkey); + invalidArgument("invalid key in `%s' element" TSRMLS_CC, id.c_str()); + throw AbortMarshaling(); } - } + keyType->marshal(zkey, os, objectMap, false TSRMLS_CC); - // - // Marshal the key. - // - if(!keyType->validate(zkey TSRMLS_CC)) - { - invalidArgument("invalid key in `%s' element" TSRMLS_CC, id.c_str()); - throw AbortMarshaling(); - } - keyType->marshal(zkey, os, objectMap TSRMLS_CC); + // + // Marshal the value. + // + if(!valueType->validate(*val TSRMLS_CC)) + { + invalidArgument("invalid value in `%s' element" TSRMLS_CC, id.c_str()); + throw AbortMarshaling(); + } + valueType->marshal(*val, os, objectMap, false TSRMLS_CC); - // - // Marshal the value. - // - if(!valueType->validate(*val TSRMLS_CC)) - { - invalidArgument("invalid value in `%s' element" TSRMLS_CC, id.c_str()); - throw AbortMarshaling(); + zend_hash_move_forward_ex(arr, &pos); } - valueType->marshal(*val, os, objectMap TSRMLS_CC); + } - zend_hash_move_forward_ex(arr, &pos); + if(optional && _variableLength) + { + os->endSize(); } } void IcePHP::DictionaryInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, - const CommunicatorInfoPtr& comm, zval* target, void* closure TSRMLS_DC) + const CommunicatorInfoPtr& comm, zval* target, void* closure, bool optional TSRMLS_DC) { + if(optional) + { + if(_variableLength) + { + is->skip(4); + } + else + { + is->skipSize(); + } + } + PrimitiveInfoPtr piKey = PrimitiveInfoPtr::dynamicCast(keyType); EnumInfoPtr enKey = EnumInfoPtr::dynamicCast(keyType); if(!enKey && (!piKey || piKey->kind == PrimitiveInfo::KindFloat || piKey->kind == PrimitiveInfo::KindDouble)) @@ -1865,7 +2183,7 @@ IcePHP::DictionaryInfo::unmarshal(const Ice::InputStreamPtr& is, const Unmarshal // A dictionary key cannot be a class (or contain one), so the key must be // available immediately. // - keyType->unmarshal(is, keyCB, comm, 0, 0 TSRMLS_CC); + keyType->unmarshal(is, keyCB, comm, 0, 0, false TSRMLS_CC); assert(keyCB->key); // @@ -1876,7 +2194,7 @@ IcePHP::DictionaryInfo::unmarshal(const Ice::InputStreamPtr& is, const Unmarshal // // Pass the key to the callback. // - valueType->unmarshal(is, valueCB, comm, zv, 0 TSRMLS_CC); + valueType->unmarshal(is, valueCB, comm, zv, 0, false TSRMLS_CC); } cb->unmarshaled(zv, target, closure TSRMLS_CC); @@ -2021,6 +2339,53 @@ IcePHP::DictionaryInfo::destroy() // // ClassInfo implementation. // +IcePHP::ClassInfo::ClassInfo(const string& ident TSRMLS_DC) : + id(ident), isAbstract(false), preserve(false), zce(0), defined(false) +{ +} + +void +IcePHP::ClassInfo::define(const string& n, bool isAbs, bool pres, zval* b, zval* i, zval* m TSRMLS_DC) +{ + const_cast<string&>(name) = n; + const_cast<bool&>(isAbstract) = isAbs; + const_cast<bool&>(preserve) = pres; + + if(b) + { + TypeInfoPtr p = Wrapper<TypeInfoPtr>::value(b TSRMLS_CC); + const_cast<ClassInfoPtr&>(base) = ClassInfoPtr::dynamicCast(p); + assert(base); + } + + if(i) + { + HashTable* interfacesArray = Z_ARRVAL_P(i); + void* data; + HashPosition pos; + zend_hash_internal_pointer_reset_ex(interfacesArray, &pos); + while(zend_hash_get_current_data_ex(interfacesArray, &data, &pos) != FAILURE) + { + zval** interfaceType = reinterpret_cast<zval**>(data); + TypeInfoPtr t = Wrapper<TypeInfoPtr>::value(*interfaceType TSRMLS_CC); + ClassInfoPtr c = ClassInfoPtr::dynamicCast(t); + assert(c); + const_cast<ClassInfoList&>(interfaces).push_back(c); + zend_hash_move_forward_ex(interfacesArray, &pos); + } + } + + if(m) + { + convertDataMembers(m, const_cast<DataMemberList&>(members), const_cast<DataMemberList&>(optionalMembers), + true TSRMLS_CC); + } + + const_cast<bool&>(defined) = true; + const_cast<zend_class_entry*&>(zce) = nameToClass(name TSRMLS_CC); + assert(zce || id == "::Ice::LocalObject"); // LocalObject does not have a native PHP equivalent. +} + string IcePHP::ClassInfo::getId() const { @@ -2032,19 +2397,31 @@ IcePHP::ClassInfo::validate(zval* val TSRMLS_DC) { if(Z_TYPE_P(val) == IS_OBJECT) { - return checkClass(Z_OBJCE_P(val), zce); + return checkClass(Z_OBJCE_P(val), const_cast<zend_class_entry*>(zce)); } return Z_TYPE_P(val) == IS_NULL; } bool -IcePHP::ClassInfo::usesClasses() +IcePHP::ClassInfo::variableLength() const { return true; } +int +IcePHP::ClassInfo::wireSize() const +{ + return 1; +} + +Ice::OptionalFormat +IcePHP::ClassInfo::optionalFormat() const +{ + return Ice::OptionalFormatSize; +} + void -IcePHP::ClassInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* objectMap TSRMLS_DC) +IcePHP::ClassInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* objectMap, bool TSRMLS_DC) { if(!defined) { @@ -2088,7 +2465,7 @@ IcePHP::ClassInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* void IcePHP::ClassInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, - const CommunicatorInfoPtr& comm, zval* target, void* closure TSRMLS_DC) + const CommunicatorInfoPtr& comm, zval* target, void* closure, bool TSRMLS_DC) { if(!defined) { @@ -2134,12 +2511,12 @@ IcePHP::ClassInfo::print(zval* zv, IceUtilInternal::Output& out, PrintObjectHist void IcePHP::ClassInfo::destroy() { - base = 0; - interfaces.clear(); + const_cast<ClassInfoPtr&>(base) = 0; + const_cast<ClassInfoList&>(interfaces).clear(); if(!members.empty()) { DataMemberList ml = members; - members.clear(); + const_cast<DataMemberList&>(members).clear(); for(DataMemberList::iterator p = ml.begin(); p != ml.end(); ++p) { (*p)->type->destroy(); @@ -2155,7 +2532,9 @@ IcePHP::ClassInfo::printMembers(zval* zv, IceUtilInternal::Output& out, PrintObj base->printMembers(zv, out, history TSRMLS_CC); } - for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q) + DataMemberList::const_iterator q; + + for(q = members.begin(); q != members.end(); ++q) { DataMemberPtr member = *q; @@ -2171,6 +2550,30 @@ IcePHP::ClassInfo::printMembers(zval* zv, IceUtilInternal::Output& out, PrintObj out << "<not defined>"; } } + + for(q = optionalMembers.begin(); q != optionalMembers.end(); ++q) + { + DataMemberPtr member = *q; + + out << nl << member->name << " = "; + void* data; + if(zend_hash_find(Z_OBJPROP_P(zv), STRCAST(member->name.c_str()), member->name.size() + 1, &data) == SUCCESS) + { + zval** val = reinterpret_cast<zval**>(data); + if(isUnset(*val TSRMLS_CC)) + { + out << "<unset>"; + } + else + { + member->type->print(*val, out, history TSRMLS_CC); + } + } + else + { + out << "<not defined>"; + } + } } bool @@ -2229,6 +2632,18 @@ IcePHP::ClassInfo::getOperation(const string& name) const // // ProxyInfo implementation. // +IcePHP::ProxyInfo::ProxyInfo(const string& ident TSRMLS_DC) : + id(ident), defined(false) +{ +} + +void +IcePHP::ProxyInfo::define(const ClassInfoPtr& c TSRMLS_DC) +{ + const_cast<ClassInfoPtr&>(cls) = c; + const_cast<bool&>(defined) = true; +} + string IcePHP::ProxyInfo::getId() const { @@ -2251,9 +2666,32 @@ IcePHP::ProxyInfo::validate(zval* zv TSRMLS_DC) return true; } +bool +IcePHP::ProxyInfo::variableLength() const +{ + return true; +} + +int +IcePHP::ProxyInfo::wireSize() const +{ + return 1; +} + +Ice::OptionalFormat +IcePHP::ProxyInfo::optionalFormat() const +{ + return Ice::OptionalFormatFSize; +} + void -IcePHP::ProxyInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* TSRMLS_DC) +IcePHP::ProxyInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap*, bool optional TSRMLS_DC) { + if(optional) + { + os->startSize(); + } + if(Z_TYPE_P(zv) == IS_NULL) { os->write(Ice::ObjectPrx()); @@ -2274,16 +2712,26 @@ IcePHP::ProxyInfo::marshal(zval* zv, const Ice::OutputStreamPtr& os, ObjectMap* } os->write(proxy); } + + if(optional) + { + os->endSize(); + } } void IcePHP::ProxyInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, - const CommunicatorInfoPtr& comm, zval* target, void* closure TSRMLS_DC) + const CommunicatorInfoPtr& comm, zval* target, void* closure, bool optional TSRMLS_DC) { zval* zv; MAKE_STD_ZVAL(zv); AutoDestroy destroy(zv); + if(optional) + { + is->skip(4); + } + Ice::ObjectPrx proxy; is->read(proxy); @@ -2335,7 +2783,7 @@ IcePHP::ProxyInfo::print(zval* zv, IceUtilInternal::Output& out, PrintObjectHist void IcePHP::ProxyInfo::destroy() { - cls = 0; + const_cast<ClassInfoPtr&>(cls) = 0; } // @@ -2357,7 +2805,7 @@ IcePHP::ObjectWriter::ObjectWriter(zval* object, ObjectMap* objectMap, const Cla // The caller may have provided a ClassInfo representing the formal type, in // which case we ensure that the actual type is compatible with the formal type. // - _info = getClassInfoByClass(Z_OBJCE_P(object), formal ? formal->zce : 0 TSRMLS_CC); + _info = getClassInfoByClass(Z_OBJCE_P(object), formal ? const_cast<zend_class_entry*>(formal->zce) : 0 TSRMLS_CC); assert(_info); } @@ -2394,40 +2842,61 @@ IcePHP::ObjectWriter::write(const Ice::OutputStreamPtr& os) const os->startObject(slicedData); - ClassInfoPtr info = _info; - while(info && info->id != Ice::Object::ice_staticId()) + if(_info->id != "::Ice::UnknownSlicedObject") { - assert(info->base); // All classes have the Ice::Object base type. - const bool lastSlice = info->base->id == Ice::Object::ice_staticId(); - os->startSlice(info->id, lastSlice); - for(DataMemberList::iterator q = info->members.begin(); q != info->members.end(); ++q) + ClassInfoPtr info = _info; + while(info && info->id != Ice::Object::ice_staticId()) { - DataMemberPtr member = *q; + assert(info->base); // All classes have the Ice::Object base type. + const bool lastSlice = info->base->id == Ice::Object::ice_staticId(); + os->startSlice(info->id, lastSlice); - void* data; - if(zend_hash_find(Z_OBJPROP_P(_object), STRCAST(member->name.c_str()), member->name.size() + 1, &data) == - FAILURE) - { - runtimeError("member `%s' of %s is not defined" TSRMLS_CC, member->name.c_str(), _info->id.c_str()); - throw AbortMarshaling(); - } + writeMembers(os, info->members); + writeMembers(os, info->optionalMembers); // The optional members have already been sorted by tag. - zval** val = reinterpret_cast<zval**>(data); - if(!member->type->validate(*val TSRMLS_CC)) - { - invalidArgument("invalid value for %s member `%s'" TSRMLS_CC, _info->id.c_str(), member->name.c_str()); - throw AbortMarshaling(); - } - member->type->marshal(*val, os, _map TSRMLS_CC); - } - os->endSlice(); + os->endSlice(); - info = info->base; + info = info->base; + } } os->endObject(); } +void +IcePHP::ObjectWriter::writeMembers(const Ice::OutputStreamPtr& os, const DataMemberList& members) const +{ + for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) + { + DataMemberPtr member = *q; + + void* data; + if(zend_hash_find(Z_OBJPROP_P(_object), STRCAST(member->name.c_str()), member->name.size() + 1, &data) == + FAILURE) + { + runtimeError("member `%s' of %s is not defined" TSRMLS_CC, member->name.c_str(), _info->id.c_str()); + throw AbortMarshaling(); + } + + zval** val = reinterpret_cast<zval**>(data); + + if(member->optional && (isUnset(*val TSRMLS_CC) || + !os->writeOptional(member->tag, member->type->optionalFormat()))) + { + continue; + } + + if(!member->type->validate(*val TSRMLS_CC)) + { + invalidArgument("invalid value for %s member `%s'" TSRMLS_CC, _info->id.c_str(), + member->name.c_str()); + throw AbortMarshaling(); + } + + member->type->marshal(*val, os, _map, member->optional TSRMLS_CC); + } +} + // // ObjectReader implementation. // @@ -2464,21 +2933,50 @@ IcePHP::ObjectReader::read(const Ice::InputStreamPtr& is) { is->startObject(); + const bool unknown = _info->id == "::Ice::UnknownSlicedObject"; + // // Unmarshal the slices of a user-defined class. // - ClassInfoPtr info = _info; - while(info && info->id != Ice::Object::ice_staticId()) + if(!unknown) { - is->startSlice(); - for(DataMemberList::iterator p = info->members.begin(); p != info->members.end(); ++p) + ClassInfoPtr info = _info; + while(info && info->id != Ice::Object::ice_staticId()) { - DataMemberPtr member = *p; - member->type->unmarshal(is, member, _communicator, _object, 0 TSRMLS_CC); - } - is->endSlice(); + is->startSlice(); - info = info->base; + DataMemberList::const_iterator p; + + for(p = info->members.begin(); p != info->members.end(); ++p) + { + DataMemberPtr member = *p; + member->type->unmarshal(is, member, _communicator, _object, 0, false TSRMLS_CC); + } + + // + // The optional members have already been sorted by tag. + // + for(p = info->optionalMembers.begin(); p != info->optionalMembers.end(); ++p) + { + DataMemberPtr member = *p; + if(is->readOptional(member->tag, member->type->optionalFormat())) + { + member->type->unmarshal(is, member, _communicator, _object, 0, true TSRMLS_CC); + } + else + { + zval* zv; + MAKE_STD_ZVAL(zv); + AutoDestroy destroy(zv); + unset(zv); + member->setMember(_object, zv TSRMLS_CC); + } + } + + is->endSlice(); + + info = info->base; + } } _slicedData = is->endObject(_info->preserve); @@ -2488,6 +2986,21 @@ IcePHP::ObjectReader::read(const Ice::InputStreamPtr& is) SlicedDataUtil* util = reinterpret_cast<SlicedDataUtil*>(is->closure()); assert(util); util->add(this); + + // + // Define the "unknownTypeId" member for an instance of UnknownSlicedObject. + // + if(unknown) + { + assert(!_slicedData->slices.empty()); + + const string typeId = _slicedData->slices[0]->typeId; + zval* zv; + MAKE_STD_ZVAL(zv); + AutoDestroy typeIdDestroyer(zv); + ZVAL_STRINGL(zv, STRCAST(typeId.c_str()), typeId.size(), 1); + add_property_zval(_object, STRCAST("unknownTypeId"), zv); + } } } @@ -2594,11 +3107,35 @@ IcePHP::ExceptionInfo::unmarshal(const Ice::InputStreamPtr& is, const Communicat while(info) { is->startSlice(); - for(DataMemberList::iterator q = info->members.begin(); q != info->members.end(); ++q) + + DataMemberList::iterator q; + + for(q = info->members.begin(); q != info->members.end(); ++q) { DataMemberPtr member = *q; - member->type->unmarshal(is, member, comm, zv, 0 TSRMLS_CC); + member->type->unmarshal(is, member, comm, zv, 0, false TSRMLS_CC); } + + // + // The optional members have already been sorted by tag. + // + for(q = info->optionalMembers.begin(); q != info->optionalMembers.end(); ++q) + { + DataMemberPtr member = *q; + if(is->readOptional(member->tag, member->type->optionalFormat())) + { + member->type->unmarshal(is, member, comm, zv, 0, true TSRMLS_CC); + } + else + { + zval* un; + MAKE_STD_ZVAL(un); + AutoDestroy destroy(un); + unset(un); + member->setMember(zv, un TSRMLS_CC); + } + } + is->endSlice(); info = info->base; @@ -2644,7 +3181,9 @@ IcePHP::ExceptionInfo::printMembers(zval* zv, IceUtilInternal::Output& out, Prin base->printMembers(zv, out, history TSRMLS_CC); } - for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q) + DataMemberList::iterator q; + + for(q = members.begin(); q != members.end(); ++q) { DataMemberPtr member = *q; @@ -2660,6 +3199,30 @@ IcePHP::ExceptionInfo::printMembers(zval* zv, IceUtilInternal::Output& out, Prin out << "<not defined>"; } } + + for(q = optionalMembers.begin(); q != optionalMembers.end(); ++q) + { + DataMemberPtr member = *q; + + out << nl << member->name << " = "; + void* data; + if(zend_hash_find(Z_OBJPROP_P(zv), STRCAST(member->name.c_str()), member->name.size() + 1, &data) == SUCCESS) + { + zval** val = reinterpret_cast<zval**>(data); + if(isUnset(*val TSRMLS_CC)) + { + out << "<unset>"; + } + else + { + member->type->print(*val, out, history TSRMLS_CC); + } + } + else + { + out << "<not defined>"; + } + } } bool @@ -2705,17 +3268,6 @@ IcePHP::ExceptionReader::read(const Ice::InputStreamPtr& is) const const_cast<Ice::SlicedDataPtr&>(_slicedData) = is->endException(_info->preserve); } -bool -IcePHP::ExceptionReader::usesClasses() const -{ - return _info->usesClasses; -} - -void -IcePHP::ExceptionReader::usesClasses(bool) -{ -} - string IcePHP::ExceptionReader::ice_name() const { @@ -2811,19 +3363,7 @@ ZEND_FUNCTION(IcePHP_defineEnum) return; } - EnumInfoPtr type = new EnumInfo(); - type->id = id; - HashTable* arr = Z_ARRVAL_P(enumerators); - 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); - assert(Z_TYPE_PP(val) == IS_STRING); - type->enumerators.push_back(Z_STRVAL_PP(val)); - zend_hash_move_forward_ex(arr, &pos); - } + EnumInfoPtr type = new EnumInfo(id, enumerators TSRMLS_CC); if(!createTypeInfo(return_value, type TSRMLS_CC)) { @@ -2831,36 +3371,6 @@ ZEND_FUNCTION(IcePHP_defineEnum) } } -static void -convertDataMembers(zval* zv, DataMemberList& l TSRMLS_DC) -{ - assert(Z_TYPE_P(zv) == IS_ARRAY); - HashTable* membersArray = Z_ARRVAL_P(zv); - void* data; - HashPosition pos; - zend_hash_internal_pointer_reset_ex(membersArray, &pos); - while(zend_hash_get_current_data_ex(membersArray, &data, &pos) != FAILURE) - { - zval** arr = reinterpret_cast<zval**>(data); - - DataMemberPtr m = new DataMember(); - zval** elem; - - assert(Z_TYPE_PP(arr) == IS_ARRAY); - HashTable* member = Z_ARRVAL_PP(arr); - assert(zend_hash_num_elements(member) == 2); - zend_hash_index_find(member, 0, reinterpret_cast<void**>(&elem)); - assert(Z_TYPE_PP(elem) == IS_STRING); - m->name = Z_STRVAL_PP(elem); - zend_hash_index_find(member, 1, reinterpret_cast<void**>(&elem)); - assert(Z_TYPE_PP(elem) == IS_OBJECT); - m->type = Wrapper<TypeInfoPtr>::value(*elem TSRMLS_CC); - l.push_back(m); - - zend_hash_move_forward_ex(membersArray, &pos); - } -} - ZEND_FUNCTION(IcePHP_defineStruct) { char* id; @@ -2875,12 +3385,7 @@ ZEND_FUNCTION(IcePHP_defineStruct) return; } - StructInfoPtr type = new StructInfo(); - type->id = id; - type->name = name; - convertDataMembers(members, type->members TSRMLS_CC); - type->zce = nameToClass(type->name TSRMLS_CC); - assert(type->zce); + StructInfoPtr type = new StructInfo(id, name, members TSRMLS_CC); if(!createTypeInfo(return_value, type TSRMLS_CC)) { @@ -2899,9 +3404,7 @@ ZEND_FUNCTION(IcePHP_defineSequence) return; } - SequenceInfoPtr type = new SequenceInfo(); - type->id = id; - type->elementType = Wrapper<TypeInfoPtr>::value(element TSRMLS_CC); + SequenceInfoPtr type = new SequenceInfo(id, element TSRMLS_CC); if(!createTypeInfo(return_value, type TSRMLS_CC)) { @@ -2921,10 +3424,30 @@ ZEND_FUNCTION(IcePHP_defineDictionary) return; } - DictionaryInfoPtr type = new DictionaryInfo(); - type->id = id; - type->keyType = Wrapper<TypeInfoPtr>::value(key TSRMLS_CC); - type->valueType = Wrapper<TypeInfoPtr>::value(value TSRMLS_CC); + DictionaryInfoPtr type = new DictionaryInfo(id, key, value TSRMLS_CC); + + if(!createTypeInfo(return_value, type TSRMLS_CC)) + { + RETURN_NULL(); + } +} + +ZEND_FUNCTION(IcePHP_declareProxy) +{ + char* id; + int idLen; + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("s"), &id, &idLen) == FAILURE) + { + return; + } + + ProxyInfoPtr type = getProxyInfo(id TSRMLS_CC); + if(!type) + { + type = new ProxyInfo(id TSRMLS_CC); + addProxyInfo(type TSRMLS_CC); + } if(!createTypeInfo(return_value, type TSRMLS_CC)) { @@ -2948,23 +3471,11 @@ ZEND_FUNCTION(IcePHP_defineProxy) ProxyInfoPtr type = getProxyInfo(c->id TSRMLS_CC); if(!type) { - type = new ProxyInfo(); - type->id = c->id; - - ProxyInfoMap* m; - if(ICE_G(proxyInfoMap)) - { - m = reinterpret_cast<ProxyInfoMap*>(ICE_G(proxyInfoMap)); - } - else - { - m = new ProxyInfoMap; - ICE_G(proxyInfoMap) = m; - } - m->insert(ProxyInfoMap::value_type(type->id, type)); + type = new ProxyInfo(c->id TSRMLS_CC); + addProxyInfo(type TSRMLS_CC); } - type->cls = c; + type->define(c TSRMLS_CC); if(!createTypeInfo(return_value, type TSRMLS_CC)) { @@ -2974,11 +3485,6 @@ ZEND_FUNCTION(IcePHP_defineProxy) ZEND_FUNCTION(IcePHP_declareClass) { - if(ZEND_NUM_ARGS() != 1) - { - WRONG_PARAM_COUNT; - } - char* id; int idLen; @@ -2987,11 +3493,12 @@ ZEND_FUNCTION(IcePHP_declareClass) return; } - ClassInfoPtr type = new ClassInfo(); - type->id = id; - type->defined = false; - - addClassInfoById(type TSRMLS_CC); + ClassInfoPtr type = getClassInfoById(id TSRMLS_CC); + if(!type) + { + type = new ClassInfo(id TSRMLS_CC); + addClassInfoById(type TSRMLS_CC); + } if(!createTypeInfo(return_value, type TSRMLS_CC)) { @@ -3020,49 +3527,13 @@ ZEND_FUNCTION(IcePHP_defineClass) ClassInfoPtr type = getClassInfoById(id TSRMLS_CC); if(!type) { - type = new ClassInfo(); - type->id = id; + type = new ClassInfo(id TSRMLS_CC); addClassInfoById(type TSRMLS_CC); } - type->name = name; + type->define(name, isAbstract ? true : false, preserve ? true : false, base, interfaces, members TSRMLS_CC); addClassInfoByName(type TSRMLS_CC); - type->isAbstract = isAbstract ? true : false; - type->preserve = preserve ? true : false; - if(base) - { - TypeInfoPtr p = Wrapper<TypeInfoPtr>::value(base TSRMLS_CC); - type->base = ClassInfoPtr::dynamicCast(p); - assert(type->base); - } - - if(interfaces) - { - HashTable* interfacesArray = Z_ARRVAL_P(interfaces); - void* data; - HashPosition pos; - zend_hash_internal_pointer_reset_ex(interfacesArray, &pos); - while(zend_hash_get_current_data_ex(interfacesArray, &data, &pos) != FAILURE) - { - zval** interfaceType = reinterpret_cast<zval**>(data); - TypeInfoPtr t = Wrapper<TypeInfoPtr>::value(*interfaceType TSRMLS_CC); - ClassInfoPtr c = ClassInfoPtr::dynamicCast(t); - assert(c); - type->interfaces.push_back(c); - zend_hash_move_forward_ex(interfacesArray, &pos); - } - } - - if(members) - { - convertDataMembers(members, type->members TSRMLS_CC); - } - - type->defined = true; - type->zce = nameToClass(type->name TSRMLS_CC); - assert(type->zce || type->id == "::Ice::LocalObject"); // LocalObject does not have a native PHP equivalent. - if(!createTypeInfo(return_value, type TSRMLS_CC)) { RETURN_NULL(); @@ -3143,16 +3614,7 @@ ZEND_FUNCTION(IcePHP_defineException) } if(members) { - convertDataMembers(members, ex->members TSRMLS_CC); - } - - ex->usesClasses = false; - for(DataMemberList::iterator p = ex->members.begin(); p != ex->members.end(); ++p) - { - if(!ex->usesClasses) - { - ex->usesClasses = (*p)->type->usesClasses(); - } + convertDataMembers(members, ex->members, ex->optionalMembers, true TSRMLS_CC); } ex->zce = nameToClass(ex->name TSRMLS_CC); @@ -3248,7 +3710,24 @@ static zend_function_entry _exceptionInfoMethods[] = }; bool -IcePHP::typesInit(TSRMLS_D) +IcePHP::isUnset(zval* zv TSRMLS_DC) +{ + if(Z_TYPE_P(zv) == IS_STRING) + { + return _unsetGUID == string(Z_STRVAL_P(zv), Z_STRLEN_P(zv)); + } + return false; +} + +void +IcePHP::unset(zval* zv TSRMLS_DC) +{ + *zv = *ICE_G(unset); + zval_copy_ctor(zv); +} + +bool +IcePHP::typesInit(INIT_FUNC_ARGS) { zend_class_entry ce; @@ -3268,6 +3747,11 @@ IcePHP::typesInit(TSRMLS_D) exceptionInfoClassEntry = zend_register_internal_class(&ce TSRMLS_CC); memcpy(&_exceptionInfoHandlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + REGISTER_STRING_CONSTANT("Ice_Unset", const_cast<char*>(_unsetGUID.c_str()), CONST_CS|CONST_PERSISTENT); +#ifdef ICEPHP_USE_NAMESPACES + REGISTER_NS_STRING_CONSTANT("Ice", "Unset", const_cast<char*>(_unsetGUID.c_str()), CONST_CS|CONST_PERSISTENT); +#endif + return true; } @@ -3298,6 +3782,11 @@ IcePHP::typesRequestInit(TSRMLS_D) ICE_G(proxyInfoMap) = 0; ICE_G(exceptionInfoMap) = 0; + zval* unset; + MAKE_STD_ZVAL(unset); + ZVAL_STRINGL(unset, STRCAST(_unsetGUID.c_str()), _unsetGUID.length(), 1); + ICE_G(unset) = unset; + return true; } @@ -3332,5 +3821,7 @@ IcePHP::typesRequestShutdown(TSRMLS_D) delete static_cast<ExceptionInfoMap*>(ICE_G(exceptionInfoMap)); + zval_ptr_dtor(&ICE_G(unset)); + return true; } diff --git a/php/src/IcePHP/Types.h b/php/src/IcePHP/Types.h index 059a5ebd8bc..4e07412bf66 100644 --- a/php/src/IcePHP/Types.h +++ b/php/src/IcePHP/Types.h @@ -25,6 +25,7 @@ ZEND_FUNCTION(IcePHP_defineEnum); ZEND_FUNCTION(IcePHP_defineStruct); ZEND_FUNCTION(IcePHP_defineSequence); ZEND_FUNCTION(IcePHP_defineDictionary); +ZEND_FUNCTION(IcePHP_declareProxy); ZEND_FUNCTION(IcePHP_defineProxy); ZEND_FUNCTION(IcePHP_declareClass); ZEND_FUNCTION(IcePHP_defineClass); @@ -112,7 +113,9 @@ public: virtual bool validate(zval* TSRMLS_DC) = 0; - virtual bool usesClasses(); // Default implementation returns false. + virtual bool variableLength() const = 0; + virtual int wireSize() const = 0; + virtual Ice::OptionalFormat optionalFormat() const = 0; virtual void unmarshaled(zval*, zval*, void* TSRMLS_DC); // Default implementation is assert(false). @@ -128,9 +131,9 @@ public: // The marshal and unmarshal functions can raise Ice exceptions, and may raise // AbortMarshaling if an error occurs. // - virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap* TSRMLS_DC) = 0; + virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap*, bool TSRMLS_DC) = 0; virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, const CommunicatorInfoPtr&, - zval*, void* TSRMLS_DC) = 0; + zval*, void*, bool TSRMLS_DC) = 0; virtual void print(zval*, IceUtilInternal::Output&, PrintObjectHistory* TSRMLS_DC) = 0; }; @@ -147,9 +150,13 @@ public: virtual bool validate(zval* TSRMLS_DC); - virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap* TSRMLS_DC); + virtual bool variableLength() const; + virtual int wireSize() const; + virtual Ice::OptionalFormat optionalFormat() const; + + virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap*, bool TSRMLS_DC); virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, const CommunicatorInfoPtr&, - zval*, void* TSRMLS_DC); + zval*, void*, bool TSRMLS_DC); virtual void print(zval*, IceUtilInternal::Output&, PrintObjectHistory* TSRMLS_DC); @@ -176,18 +183,24 @@ class EnumInfo : public TypeInfo { public: + EnumInfo(const std::string&, zval* TSRMLS_DC); + virtual std::string getId() const; virtual bool validate(zval* TSRMLS_DC); - virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap* TSRMLS_DC); + virtual bool variableLength() const; + virtual int wireSize() const; + virtual Ice::OptionalFormat optionalFormat() const; + + virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap*, bool TSRMLS_DC); virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, const CommunicatorInfoPtr&, - zval*, void* TSRMLS_DC); + zval*, void*, bool TSRMLS_DC); virtual void print(zval*, IceUtilInternal::Output&, PrintObjectHistory* TSRMLS_DC); - std::string id; - Ice::StringSeq enumerators; + const std::string id; + const Ice::StringSeq enumerators; }; typedef IceUtil::Handle<EnumInfo> EnumInfoPtr; @@ -197,8 +210,12 @@ public: virtual void unmarshaled(zval*, zval*, void* TSRMLS_DC); + void setMember(zval*, zval* TSRMLS_DC); + std::string name; TypeInfoPtr type; + bool optional; + int tag; }; typedef IceUtil::Handle<DataMember> DataMemberPtr; typedef std::vector<DataMemberPtr> DataMemberList; @@ -210,24 +227,33 @@ class StructInfo : public TypeInfo { public: + StructInfo(const std::string&, const std::string&, zval* TSRMLS_DC); + virtual std::string getId() const; virtual bool validate(zval* TSRMLS_DC); - virtual bool usesClasses(); + virtual bool variableLength() const; + virtual int wireSize() const; + virtual Ice::OptionalFormat optionalFormat() const; - virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap* TSRMLS_DC); + virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap*, bool TSRMLS_DC); virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, const CommunicatorInfoPtr&, - zval*, void* TSRMLS_DC); + zval*, void*, bool TSRMLS_DC); virtual void print(zval*, IceUtilInternal::Output&, PrintObjectHistory* TSRMLS_DC); virtual void destroy(); - std::string id; - std::string name; // PHP class name - DataMemberList members; - zend_class_entry* zce; + const std::string id; + const std::string name; // PHP class name + const DataMemberList members; + const zend_class_entry* zce; + +private: + + bool _variableLength; + int _wireSize; }; typedef IceUtil::Handle<StructInfo> StructInfoPtr; @@ -238,15 +264,19 @@ class SequenceInfo : public TypeInfo { public: + SequenceInfo(const std::string&, zval* TSRMLS_DC); + virtual std::string getId() const; virtual bool validate(zval* TSRMLS_DC); - virtual bool usesClasses(); + virtual bool variableLength() const; + virtual int wireSize() const; + virtual Ice::OptionalFormat optionalFormat() const; - virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap* TSRMLS_DC); + virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap*, bool TSRMLS_DC); virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, const CommunicatorInfoPtr&, - zval*, void* TSRMLS_DC); + zval*, void*, bool TSRMLS_DC); virtual void print(zval*, IceUtilInternal::Output&, PrintObjectHistory* TSRMLS_DC); @@ -254,8 +284,8 @@ public: virtual void destroy(); - std::string id; - TypeInfoPtr elementType; + const std::string id; + const TypeInfoPtr elementType; private: @@ -272,15 +302,19 @@ class DictionaryInfo : public TypeInfo { public: + DictionaryInfo(const std::string&, zval*, zval* TSRMLS_DC); + virtual std::string getId() const; virtual bool validate(zval* TSRMLS_DC); - virtual bool usesClasses(); + virtual bool variableLength() const; + virtual int wireSize() const; + virtual Ice::OptionalFormat optionalFormat() const; - virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap* TSRMLS_DC); + virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap*, bool TSRMLS_DC); virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, const CommunicatorInfoPtr&, - zval*, void* TSRMLS_DC); + zval*, void*, bool TSRMLS_DC); virtual void print(zval*, IceUtilInternal::Output&, PrintObjectHistory* TSRMLS_DC); @@ -315,6 +349,11 @@ public: std::string id; TypeInfoPtr keyType; TypeInfoPtr valueType; + +private: + + bool _variableLength; + int _wireSize; }; typedef IceUtil::Handle<DictionaryInfo> DictionaryInfoPtr; @@ -332,15 +371,21 @@ class ClassInfo : public TypeInfo { public: + ClassInfo(const std::string& TSRMLS_DC); + + void define(const std::string&, bool, bool, zval*, zval*, zval* TSRMLS_DC); + virtual std::string getId() const; virtual bool validate(zval* TSRMLS_DC); - virtual bool usesClasses(); + virtual bool variableLength() const; + virtual int wireSize() const; + virtual Ice::OptionalFormat optionalFormat() const; - virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap* TSRMLS_DC); + virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap*, bool TSRMLS_DC); virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, const CommunicatorInfoPtr&, - zval*, void* TSRMLS_DC); + zval*, void*, bool TSRMLS_DC); virtual void print(zval*, IceUtilInternal::Output&, PrintObjectHistory* TSRMLS_DC); @@ -353,15 +398,16 @@ public: void addOperation(const std::string&, const OperationPtr&); OperationPtr getOperation(const std::string&) const; - std::string id; - std::string name; // PHP class name - bool isAbstract; - bool preserve; - ClassInfoPtr base; - ClassInfoList interfaces; - DataMemberList members; + const std::string id; + const std::string name; // PHP class name + const bool isAbstract; + const bool preserve; + const ClassInfoPtr base; + const ClassInfoList interfaces; + const DataMemberList members; + const DataMemberList optionalMembers; + const zend_class_entry* zce; bool defined; - zend_class_entry* zce; typedef std::map<std::string, OperationPtr> OperationMap; OperationMap operations; @@ -374,20 +420,29 @@ class ProxyInfo : public TypeInfo { public: + ProxyInfo(const std::string& TSRMLS_DC); + + void define(const ClassInfoPtr& TSRMLS_DC); + virtual std::string getId() const; virtual bool validate(zval* TSRMLS_DC); - virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap* TSRMLS_DC); + virtual bool variableLength() const; + virtual int wireSize() const; + virtual Ice::OptionalFormat optionalFormat() const; + + virtual void marshal(zval*, const Ice::OutputStreamPtr&, ObjectMap*, bool TSRMLS_DC); virtual void unmarshal(const Ice::InputStreamPtr&, const UnmarshalCallbackPtr&, const CommunicatorInfoPtr&, - zval*, void* TSRMLS_DC); + zval*, void*, bool TSRMLS_DC); virtual void print(zval*, IceUtilInternal::Output&, PrintObjectHistory* TSRMLS_DC); virtual void destroy(); - std::string id; - ClassInfoPtr cls; + const std::string id; + const ClassInfoPtr cls; + bool defined; }; typedef IceUtil::Handle<ProxyInfo> ProxyInfoPtr; @@ -410,7 +465,7 @@ public: bool preserve; ExceptionInfoPtr base; DataMemberList members; - bool usesClasses; + DataMemberList optionalMembers; zend_class_entry* zce; }; @@ -418,7 +473,10 @@ ClassInfoPtr getClassInfoById(const std::string& TSRMLS_DC); ClassInfoPtr getClassInfoByName(const std::string& TSRMLS_DC); ExceptionInfoPtr getExceptionInfo(const std::string& TSRMLS_DC); -bool typesInit(TSRMLS_D); +bool isUnset(zval* TSRMLS_DC); +void unset(zval* TSRMLS_DC); + +bool typesInit(INIT_FUNC_ARGS); bool typesRequestInit(TSRMLS_D); bool typesRequestShutdown(TSRMLS_D); @@ -438,6 +496,8 @@ public: private: + void writeMembers(const Ice::OutputStreamPtr&, const DataMemberList&) const; + zval* _object; ObjectMap* _map; ClassInfoPtr _info; @@ -488,8 +548,6 @@ public: ~ExceptionReader() throw(); virtual void read(const Ice::InputStreamPtr&) const; - virtual bool usesClasses() const; - virtual void usesClasses(bool); virtual std::string ice_name() const; virtual ExceptionReader* ice_clone() const; diff --git a/php/test/Ice/Makefile b/php/test/Ice/Makefile index 8aa9b1b4cc1..03fa41079bf 100644 --- a/php/test/Ice/Makefile +++ b/php/test/Ice/Makefile @@ -11,7 +11,8 @@ top_srcdir = ../.. include $(top_srcdir)/config/Make.rules.php -SUBDIRS = binding checksum exceptions facets info inheritance objects operations proxy slicing defaultValue +SUBDIRS = binding checksum exceptions facets info inheritance objects operations proxy slicing defaultValue \ + optional $(EVERYTHING):: @for subdir in $(SUBDIRS); \ diff --git a/php/test/Ice/Makefile.mak b/php/test/Ice/Makefile.mak index 3a850306641..fdf514dc7b7 100644 --- a/php/test/Ice/Makefile.mak +++ b/php/test/Ice/Makefile.mak @@ -11,7 +11,8 @@ top_srcdir = ..\.. !include $(top_srcdir)\config\Make.rules.mak.php
-SUBDIRS = binding checksum exceptions facets info inheritance objects operations proxy slicing defaultValue
+SUBDIRS = binding checksum exceptions facets info inheritance objects operations proxy slicing defaultValue \
+ optional
$(EVERYTHING)::
@for %i in ( $(SUBDIRS) ) do \
diff --git a/php/test/Ice/optional/.depend b/php/test/Ice/optional/.depend new file mode 100644 index 00000000000..ef3f3f858ca --- /dev/null +++ b/php/test/Ice/optional/.depend @@ -0,0 +1,2 @@ +ClientPrivate.php: ClientPrivate.ice ./Test.ice $(SLICE2PHP) $(SLICEPARSERLIB) +Test.php: Test.ice $(SLICE2PHP) $(SLICEPARSERLIB) diff --git a/php/test/Ice/optional/.depend.mak b/php/test/Ice/optional/.depend.mak new file mode 100644 index 00000000000..c0d82ee1596 --- /dev/null +++ b/php/test/Ice/optional/.depend.mak @@ -0,0 +1,2 @@ +ClientPrivate.php: ClientPrivate.ice ./Test.ice "$(SLICE2PHP)" "$(SLICEPARSERLIB)" +Test.php: Test.ice "$(SLICE2PHP)" "$(SLICEPARSERLIB)" diff --git a/php/test/Ice/optional/.gitignore b/php/test/Ice/optional/.gitignore new file mode 100644 index 00000000000..a3053d5debf --- /dev/null +++ b/php/test/Ice/optional/.gitignore @@ -0,0 +1,2 @@ +ClientPrivate.php +Test.php diff --git a/php/test/Ice/optional/Client.php b/php/test/Ice/optional/Client.php new file mode 100644 index 00000000000..f3f8b469da4 --- /dev/null +++ b/php/test/Ice/optional/Client.php @@ -0,0 +1,736 @@ +<? +// ********************************************************************** +// +// Copyright (c) 2003-2012 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. +// +// ********************************************************************** + +error_reporting(E_ALL | E_STRICT); + +if(!extension_loaded("ice")) +{ + echo "\nerror: Ice extension is not loaded.\n\n"; + exit(1); +} + +$NS = function_exists("Ice\\initialize"); +require_once ($NS ? 'Ice_ns.php' : 'Ice.php'); +require_once 'ClientPrivate.php'; + +function test($b) +{ + if(!$b) + { + $bt = debug_backtrace(); + die("\ntest failed in ".$bt[0]["file"]." line ".$bt[0]["line"]."\n"); + } +} + +function allTests($communicator) +{ + global $NS; + + $enum = $NS ? constant("Test\\MyEnum::MyEnumMember") : constant("Test_MyEnum::MyEnumMember"); + + echo "testing stringToProxy... "; + flush(); + $ref = "initial:default -p 12010"; + $base = $communicator->stringToProxy($ref); + echo "ok\n"; + + echo "testing checked cast... "; + flush(); + $initial = $base->ice_checkedCast("::Test::Initial"); + echo "ok\n"; + + echo "testing optional data members... "; + flush(); + + $oocls = $NS ? "Test\\OneOptional" : "Test_OneOptional"; + $oo1 = new $oocls; + test($oo1->a == Ice_Unset); + $oo1->a = 15; + + $oo2 = new $oocls(16); + test($oo2->a == 16); + + $mocls = $NS ? "Test\\MultiOptional" : "Test_MultiOptional"; + $mo1 = new $mocls; + test($mo1->a == Ice_Unset); + test($mo1->b == Ice_Unset); + test($mo1->c == Ice_Unset); + test($mo1->d == Ice_Unset); + test($mo1->e == Ice_Unset); + test($mo1->f == Ice_Unset); + test($mo1->g == Ice_Unset); + test($mo1->h == Ice_Unset); + test($mo1->i == Ice_Unset); + test($mo1->j == Ice_Unset); + test($mo1->k == Ice_Unset); + test($mo1->bs == Ice_Unset); + test($mo1->ss == Ice_Unset); + test($mo1->iid == Ice_Unset); + test($mo1->sid == Ice_Unset); + test($mo1->fs == Ice_Unset); + test($mo1->vs == Ice_Unset); + + test($mo1->shs == Ice_Unset); + test($mo1->es == Ice_Unset); + test($mo1->fss == Ice_Unset); + test($mo1->vss == Ice_Unset); + test($mo1->oos == Ice_Unset); + test($mo1->oops == Ice_Unset); + + test($mo1->ied == Ice_Unset); + test($mo1->ifsd == Ice_Unset); + test($mo1->ivsd == Ice_Unset); + test($mo1->iood == Ice_Unset); + test($mo1->ioopd == Ice_Unset); + + test($mo1->bos == Ice_Unset); + + $fscls = $NS ? "Test\\FixedStruct" : "Test_FixedStruct"; + $fs = new $fscls(78); + $vscls = $NS ? "Test\\VarStruct" : "Test_VarStruct"; + $vs = new $vscls("hello"); + $prx = $communicator->stringToProxy("test"); + $moprx = $NS ? eval("return Test\\MultiOptionalPrxHelper::uncheckedCast(\$prx);") : + eval("return Test_MultiOptionalPrxHelper::uncheckedCast(\$prx);"); + $ooprx = $NS ? eval("return Test\\OneOptionalPrxHelper::uncheckedCast(\$prx);") : + eval("return Test_OneOptionalPrxHelper::uncheckedCast(\$prx);"); + $oo15 = new $oocls(15); + $mocls = $NS ? "Test\\MultiOptional" : "Test_MultiOptional"; + $mo1 = new $mocls(15, true, 19, 78, 99, 5.5, 1.0, 'test', $enum, + $moprx, null, array(5), array('test', 'test2'), array(4=>3), array('test'=>10), + $fs, $vs, array(1), array($enum, $enum), array($fs), array($vs), array($oo1), + array($ooprx), array(4=>$enum), array(4=>$fs), array(5=>$vs), + array(5=>$oo15), array(5=>$ooprx), array(false, true, false)); + + test($mo1->a == 15); + test($mo1->b == true); + test($mo1->c == 19); + test($mo1->d == 78); + test($mo1->e == 99); + test($mo1->f == 5.5); + test($mo1->g == 1.0); + test($mo1->h == "test"); + test($mo1->i == $enum); + test($mo1->j == $moprx); + test($mo1->k == null); + test($mo1->bs == array(5)); + test($mo1->ss == array("test", "test2")); + test($mo1->iid[4] == 3); + test($mo1->sid["test"] == 10); + test($mo1->fs == $fs); + test($mo1->vs == $vs); + + test($mo1->shs[0] == 1); + test($mo1->es[0] == $enum && $mo1->es[1] == $enum); + test($mo1->fss[0] == $fs); + test($mo1->vss[0] == $vs); + test($mo1->oos[0] == $oo1); + test($mo1->oops[0] == $ooprx); + + test($mo1->ied[4] == $enum); + test($mo1->ifsd[4] == $fs); + test($mo1->ivsd[5] == $vs); + test($mo1->iood[5]->a == 15); + test($mo1->ioopd[5] == $ooprx); + + test($mo1->bos == array(false, true, false)); + + echo "ok\n"; + + echo "testing marshaling... "; + flush(); + + $oo4 = $initial->pingPong(new $oocls); + test($oo4->a == Ice_Unset); + + $oo5 = $initial->pingPong($oo1); + test($oo1->a == $oo5->a); + + $mo4 = $initial->pingPong(new $mocls); + test($mo4->a == Ice_Unset); + test($mo4->b == Ice_Unset); + test($mo4->c == Ice_Unset); + test($mo4->d == Ice_Unset); + test($mo4->e == Ice_Unset); + test($mo4->f == Ice_Unset); + test($mo4->g == Ice_Unset); + test($mo4->h == Ice_Unset); + test($mo4->i == Ice_Unset); + test($mo4->j == Ice_Unset); + test($mo4->k == Ice_Unset); + test($mo4->bs == Ice_Unset); + test($mo4->ss == Ice_Unset); + test($mo4->iid == Ice_Unset); + test($mo4->sid == Ice_Unset); + test($mo4->fs == Ice_Unset); + test($mo4->vs == Ice_Unset); + + test($mo4->shs == Ice_Unset); + test($mo4->es == Ice_Unset); + test($mo4->fss == Ice_Unset); + test($mo4->vss == Ice_Unset); + test($mo4->oos == Ice_Unset); + test($mo4->oops == Ice_Unset); + + test($mo4->ied == Ice_Unset); + test($mo4->ifsd == Ice_Unset); + test($mo4->ivsd == Ice_Unset); + test($mo4->iood == Ice_Unset); + test($mo4->ioopd == Ice_Unset); + + test($mo4->bos == Ice_Unset); + + $mo5 = $initial->pingPong($mo1); + test($mo5->a == $mo1->a); + test($mo5->b == $mo1->b); + test($mo5->c == $mo1->c); + test($mo5->d == $mo1->d); + test($mo5->e == $mo1->e); + test($mo5->f == $mo1->f); + test($mo5->g == $mo1->g); + test($mo5->h == $mo1->h); + test($mo5->i == $mo1->i); + test($mo5->j == $mo1->j); + test($mo5->k == null); + test($mo5->bs[0] == 5); + test($mo5->ss == $mo1->ss); + test($mo5->iid[4] == 3); + test($mo5->sid["test"] == 10); + test($mo5->fs == $mo1->fs); + test($mo5->vs == $mo1->vs); + test($mo5->shs == $mo1->shs); + test($mo5->es[0] == $enum && $mo1->es[1] == $enum); + test($mo5->fss[0] == $fs); + test($mo5->vss[0] == $vs); + test($mo5->oos[0]->a == 15); + test($mo5->oops[0] == $ooprx); + + test($mo5->ied[4] == $enum); + test($mo5->ifsd[4] == $fs); + test($mo5->ivsd[5] == $vs); + test($mo5->iood[5]->a == 15); + test($mo5->ioopd[5] == $ooprx); + + test($mo5->bos == $mo1->bos); + + // Clear the first half of the optional members + $mo6 = new $mocls; + $mo6->b = $mo5->b; + $mo6->d = $mo5->d; + $mo6->f = $mo5->f; + $mo6->h = $mo5->h; + $mo6->j = $mo5->j; + $mo6->bs = $mo5->bs; + $mo6->iid = $mo5->iid; + $mo6->fs = $mo5->fs; + $mo6->shs = $mo5->shs; + $mo6->fss = $mo5->fss; + $mo6->oos = $mo5->oos; + $mo6->ifsd = $mo5->ifsd; + $mo6->iood = $mo5->iood; + $mo6->bos = $mo5->bos; + + $mo7 = $initial->pingPong($mo6); + test($mo7->a == Ice_Unset); + test($mo7->b == $mo1->b); + test($mo7->c == Ice_Unset); + test($mo7->d == $mo1->d); + test($mo7->e == Ice_Unset); + test($mo7->f == $mo1->f); + test($mo7->g == Ice_Unset); + test($mo7->h == $mo1->h); + test($mo7->i == Ice_Unset); + test($mo7->j == $mo1->j); + test($mo7->k == Ice_Unset); + test($mo7->bs[0] == 5); + test($mo7->ss == Ice_Unset); + test($mo7->iid[4] == 3); + test($mo7->sid == Ice_Unset); + test($mo7->fs == $mo1->fs); + test($mo7->vs == Ice_Unset); + + test($mo7->shs == $mo1->shs); + test($mo7->es == Ice_Unset); + test($mo7->fss[0] == $fs); + test($mo7->vss == Ice_Unset); + test($mo7->oos[0]->a == 15); + test($mo7->oops == Ice_Unset); + + test($mo7->ied == Ice_Unset); + test($mo7->ifsd[4] == $fs); + test($mo7->ivsd == Ice_Unset); + test($mo7->iood[5]->a == 15); + test($mo7->ioopd == Ice_Unset); + + test($mo7->bos == array(false, true, false)); + + // Clear the second half of the optional members + $mo8 = new $mocls; + $mo8->a = $mo5->a; + $mo8->c = $mo5->c; + $mo8->e = $mo5->e; + $mo8->g = $mo5->g; + $mo8->i = $mo5->i; + $mo8->k = $mo8; + $mo8->ss = $mo5->ss; + $mo8->sid = $mo5->sid; + $mo8->vs = $mo5->vs; + + $mo8->es = $mo5->es; + $mo8->vss = $mo5->vss; + $mo8->oops = $mo5->oops; + + $mo8->ied = $mo5->ied; + $mo8->ivsd = $mo5->ivsd; + $mo8->ioopd = $mo5->ioopd; + + $mo9 = $initial->pingPong($mo8); + test($mo9->a == $mo1->a); + test($mo9->b == Ice_Unset); + test($mo9->c == $mo1->c); + test($mo9->d == Ice_Unset); + test($mo9->e == $mo1->e); + test($mo9->f == Ice_Unset); + test($mo9->g == $mo1->g); + test($mo9->h == Ice_Unset); + test($mo9->i == $mo1->i); + test($mo9->j == Ice_Unset); + test($mo9->k == $mo9); + test($mo9->bs == Ice_Unset); + test($mo9->ss == $mo1->ss); + test($mo9->iid == Ice_Unset); + test($mo9->sid["test"] == 10); + test($mo9->fs == Ice_Unset); + test($mo9->vs == $mo1->vs); + + test($mo9->shs == Ice_Unset); + test($mo9->es[0] == $enum && $mo1->es[1] == $enum); + test($mo9->fss == Ice_Unset); + test($mo9->vss[0] == $vs); + test($mo9->oos == Ice_Unset); + test($mo9->oops[0] == $ooprx); + + test($mo9->ied[4] == $enum); + test($mo9->ifsd == Ice_Unset); + test($mo9->ivsd[5] == $vs); + test($mo9->iood == Ice_Unset); + test($mo9->ioopd[5] == $ooprx); + + test($mo9->bos == Ice_Unset); + + echo "ok\n"; + + echo "testing marshaling of large containers with fixed size elements... "; + flush(); + + $mc = new $mocls; + $mc->bs = array(); + for($i = 0; $i < 1000; $i++) + { + $mc->bs[$i] = 0; + } + $mc->shs = array(); + for($i = 0; $i < 300; $i++) + { + $mc->shs[$i] = 0; + } + $mc->fss = array(); + for($i = 0; $i < 300; $i++) + { + $mc->fss[$i] = new $fscls; + } + $mc->ifsd = array(); + for($i = 0; $i < 300; $i++) + { + $mc->ifsd[$i] = new $fscls; + } + + $mc = $initial->pingPong($mc); + test(count($mc->bs) == 1000); + test(count($mc->shs) == 300); + test(count($mc->fss) == 300); + test(count($mc->ifsd) == 300); + + echo "ok\n"; + + echo "testing tag marshaling... "; + flush(); + + $bcls = $NS ? "Test\\B" : "Test_B"; + $b = new $bcls; + $b2 = $initial->pingPong($b); + test($b2->ma == Ice_Unset); + test($b2->mb == Ice_Unset); + test($b2->mc == Ice_Unset); + + $b->ma = 10; + $b->mb = 11; + $b->mc = 12; + $b->md = 13; + + $b2 = $initial->pingPong($b); + test($b2->ma == 10); + test($b2->mb == 11); + test($b2->mc == 12); + test($b2->md == 13); + + echo "ok\n"; + + echo "testing optional with default values... "; + flush(); + + $wdcls = $NS ? "Test\\WD" : "Test_WD"; + $wd = $initial->pingPong(new $wdcls); + test($wd->a == 5); + test($wd->s == "test"); + $wd->a = Ice_Unset; + $wd->s = Ice_Unset; + $wd = $initial->pingPong($wd); + test($wd->a == Ice_Unset); + test($wd->s == Ice_Unset); + + echo "ok\n"; + + if($communicator->getProperties()->getPropertyAsInt("Ice.Default.SlicedFormat") > 0) + { + echo "testing marshaling with unknown class slices... "; + flush(); + + $ccls = $NS ? "Test\\C" : "Test_C"; + $c = new $ccls; + $c->ss = "test"; + $c->ms = "testms"; + $c = $initial->pingPong($c); + test($c->ma == Ice_Unset); + test($c->mb == Ice_Unset); + test($c->mc == Ice_Unset); + test($c->md == Ice_Unset); + test($c->ss == "test"); + test($c->ms == "testms"); + + echo "ok\n"; + + echo "testing optionals with unknown classes... "; + flush(); + + $initial2 = $NS ? eval("return Test\\Initial2PrxHelper::uncheckedCast(\$base);") : + eval("return Test_Initial2PrxHelper::uncheckedCast(\$base);"); + $acls = $NS ? "Test\\A" : "Test_A"; + $dcls = $NS ? "Test\\D" : "Test_D"; + $d = new $dcls; + $d->ds = "test"; + $d->seq = array("test1", "test2", "test3", "test4"); + $d->ao = new $acls(18); + $d->requiredB = 14; + $d->requiredA = 14; + $initial2->opClassAndUnknownOptional(new $acls, $d); + + echo "ok\n"; + } + + echo "testing optional parameters... "; + flush(); + + $p2 = 0; + $p3 = $initial->opByte(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p3 = $initial->opByte(56, $p2); + test($p2 == 56 && $p3 == 56); + + $p3 = $initial->opBool(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p3 = $initial->opBool(true, $p2); + test($p2 == true && $p3 == true); + + $p3 = $initial->opShort(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p3 = $initial->opShort(56, $p2); + test($p2 == 56 && $p3 == 56); + + $p3 = $initial->opInt(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p3 = $initial->opInt(56, $p2); + test($p2 == 56 && $p3 == 56); + + $p3 = $initial->opLong(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p3 = $initial->opLong(56, $p2); + test($p2 == 56 && $p3 == 56); + + $p3 = $initial->opFloat(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p3 = $initial->opFloat(1.0, $p2); + test($p2 == 1.0 && $p3 == 1.0); + + $p3 = $initial->opDouble(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p3 = $initial->opDouble(1.0, $p2); + test($p2 == 1.0 && $p3 == 1.0); + + $p3 = $initial->opString(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p3 = $initial->opString("test", $p2); + test($p2 == "test" && $p3 == "test"); + + $p3 = $initial->opMyEnum(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p3 = $initial->opMyEnum($enum, $p2); + test($p2 == $enum && $p3 == $enum); + + $sscls = $NS ? "Test\\SmallStruct" : "Test_SmallStruct"; + $p3 = $initial->opSmallStruct(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = new $sscls(56); + $p3 = $initial->opSmallStruct($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opFixedStruct(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = new $fscls(56); + $p3 = $initial->opFixedStruct($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opVarStruct(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = new $vscls("test"); + $p3 = $initial->opVarStruct($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opOneOptional(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = new $oocls(58); + $p3 = $initial->opOneOptional($p1, $p2); + test($p2->a == $p1->a && $p3->a == $p1->a); + + $p3 = $initial->opOneOptionalProxy(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p3 = $initial->opOneOptionalProxy($ooprx, $p2); + test($p2 == $ooprx && $p3 == $ooprx); + + $p3 = $initial->opByteSeq(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = array(); + for($i = 0; $i < 100; $i++) + { + $p1[$i] = 56; + } + $p3 = $initial->opByteSeq($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opBoolSeq(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = array(); + for($i = 0; $i < 100; $i++) + { + $p1[$i] = true; + } + $p3 = $initial->opBoolSeq($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opShortSeq(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = array(); + for($i = 0; $i < 100; $i++) + { + $p1[$i] = 56; + } + $p3 = $initial->opShortSeq($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opIntSeq(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = array(); + for($i = 0; $i < 100; $i++) + { + $p1[$i] = 56; + } + $p3 = $initial->opIntSeq($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opLongSeq(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = array(); + for($i = 0; $i < 100; $i++) + { + $p1[$i] = 56; + } + $p3 = $initial->opLongSeq($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opFloatSeq(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = array(); + for($i = 0; $i < 100; $i++) + { + $p1[$i] = 1.0; + } + $p3 = $initial->opFloatSeq($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opDoubleSeq(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = array(); + for($i = 0; $i < 100; $i++) + { + $p1[$i] = 1.0; + } + $p3 = $initial->opDoubleSeq($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opStringSeq(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = array(); + for($i = 0; $i < 100; $i++) + { + $p1[$i] = "test1"; + } + $p3 = $initial->opStringSeq($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opSmallStructSeq(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = array(); + for($i = 0; $i < 10; $i++) + { + $p1[$i] = new $sscls(1); + } + $p3 = $initial->opSmallStructSeq($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opFixedStructSeq(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = array(); + for($i = 0; $i < 10; $i++) + { + $p1[$i] = new $fscls(1); + } + $p3 = $initial->opFixedStructSeq($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opVarStructSeq(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = array(); + for($i = 0; $i < 10; $i++) + { + $p1[$i] = new $vscls("test"); + } + $p3 = $initial->opVarStructSeq($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opIntIntDict(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = array(1=>2, 2=>3); + $p3 = $initial->opIntIntDict($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + $p3 = $initial->opStringIntDict(Ice_Unset, $p2); + test($p2 == Ice_Unset && $p3 == Ice_Unset); + $p1 = array("1"=>2, "2"=>3); + $p3 = $initial->opStringIntDict($p1, $p2); + test($p2 == $p1 && $p3 == $p1); + + echo "ok\n"; + + echo "testing exception optionals... "; + flush(); + + try + { + $initial->opOptionalException(Ice_Unset, Ice_Unset, Ice_Unset); + } + catch(Exception $ex) + { + $excls = $NS ? "Test\\OptionalException" : "Test_OptionalException"; + if(!($ex instanceof $excls)) + { + throw $ex; + } + test($ex->a == Ice_Unset); + test($ex->b == Ice_Unset); + test($ex->o == Ice_Unset); + } + + try + { + $initial->opOptionalException(30, "test", new $oocls(53)); + } + catch(Exception $ex) + { + test($ex->a == 30); + test($ex->b == "test"); + test($ex->o->a == 53); + } + + try + { + $initial->opDerivedException(Ice_Unset, Ice_Unset, Ice_Unset); + } + catch(Exception $ex) + { + test($ex->a == Ice_Unset); + test($ex->b == Ice_Unset); + test($ex->o == Ice_Unset); + test($ex->ss == Ice_Unset); + test($ex->o2 == Ice_Unset); + } + + try + { + $initial->opDerivedException(30, "test", new $oocls(53)); + } + catch(Exception $ex) + { + test($ex->a == 30); + test($ex->b == "test"); + test($ex->o->a == 53); + test($ex->ss == "test"); + test($ex->o2 == $ex->o); + } + + try + { + $initial->opRequiredException(Ice_Unset, Ice_Unset, Ice_Unset); + } + catch(Exception $ex) + { + test($ex->a == Ice_Unset); + test($ex->b == Ice_Unset); + test($ex->o == Ice_Unset); + test($ex->ss != Ice_Unset); + test($ex->o2 != Ice_Unset); + } + + try + { + $initial->opRequiredException(30, "test", new $oocls(53)); + } + catch(Exception $ex) + { + test($ex->a == 30); + test($ex->b == "test"); + test($ex->o->a == 53); + test($ex->ss == "test"); + test($ex->o2 == $ex->o); + } + + echo "ok\n"; + + return $initial; +} + +$communicator = Ice_initialize($argv); + +$initial = allTests($communicator); + +$initial->shutdown(); +$communicator->destroy(); + +exit(); +?> diff --git a/php/test/Ice/optional/ClientPrivate.ice b/php/test/Ice/optional/ClientPrivate.ice new file mode 100644 index 00000000000..a456124b4ec --- /dev/null +++ b/php/test/Ice/optional/ClientPrivate.ice @@ -0,0 +1,37 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2012 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. +// +// ********************************************************************** + +#pragma once + +#include <Test.ice> + +module Test +{ + +// +// The server doesn't know this class. +// +class D extends B +{ + string ds; + optional(990) StringSeq seq; + optional(1000) A ao; +}; + +// +// This class is a hack that allows us to invoke the opClassAndUnknownOptional operation +// on the server and pass an optional argument. This isn't necessary in other language +// mappings where the public stream API is available. +// +class Initial2 +{ + void opClassAndUnknownOptional(A p, optional(1) Object o); +}; + +}; diff --git a/php/test/Ice/optional/Makefile b/php/test/Ice/optional/Makefile new file mode 100644 index 00000000000..a390fe5e62b --- /dev/null +++ b/php/test/Ice/optional/Makefile @@ -0,0 +1,27 @@ +# ********************************************************************** +# +# Copyright (c) 2003-2012 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. +# +# ********************************************************************** + +top_srcdir = ../../.. + +SLICE_SRCS = ClientPrivate.ice Test.ice + +include $(top_srcdir)/config/Make.rules.php + +SRCS = ClientPrivate.php Test.php +SLICE2PHPFLAGS := -I. $(SLICE2PHPFLAGS) + +all:: $(SRCS) + +%.php: %.ice + $(SLICE2PHP) $(SLICE2PHPFLAGS) $< + +clean:: + rm -f $(SRCS) + +include .depend diff --git a/php/test/Ice/optional/Makefile.mak b/php/test/Ice/optional/Makefile.mak new file mode 100644 index 00000000000..7d43d824315 --- /dev/null +++ b/php/test/Ice/optional/Makefile.mak @@ -0,0 +1,25 @@ +# **********************************************************************
+#
+# Copyright (c) 2003-2012 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.
+#
+# **********************************************************************
+
+top_srcdir = ..\..\..
+
+!include $(top_srcdir)\config\Make.rules.mak.php
+
+SRCS = ClientPrivate.php Test.php
+SLICE2PHPFLAGS = -I. $(SLICE2PHPFLAGS)
+
+all:: $(SRCS)
+
+$(SRCS): $*.ice
+ -"$(SLICE2PHP)" $(SLICE2PHPFLAGS) $*.ice
+
+clean::
+ del /q $(SRCS)
+
+include .depend.mak
diff --git a/php/test/Ice/optional/Test.ice b/php/test/Ice/optional/Test.ice new file mode 100644 index 00000000000..7f0342b8df4 --- /dev/null +++ b/php/test/Ice/optional/Test.ice @@ -0,0 +1,246 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2012 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. +// +// ********************************************************************** + +#pragma once + +module Test +{ + +class OneOptional +{ + optional(1) int a; +}; + +enum MyEnum +{ + MyEnumMember +}; + +struct SmallStruct +{ + byte m; +}; + +struct FixedStruct +{ + int m; +}; + +struct VarStruct +{ + string m; +}; + +struct ClassVarStruct +{ + int a; +}; + +sequence<byte> ByteSeq; +sequence<bool> BoolSeq; +sequence<short> ShortSeq; +sequence<int> IntSeq; +sequence<long> LongSeq; +sequence<float> FloatSeq; +sequence<double> DoubleSeq; +sequence<string> StringSeq; +sequence<MyEnum> MyEnumSeq; +sequence<SmallStruct> SmallStructSeq; +sequence<SmallStruct> SmallStructList; +sequence<FixedStruct> FixedStructSeq; +sequence<FixedStruct> FixedStructList; +sequence<VarStruct> VarStructSeq; +sequence<OneOptional> OneOptionalSeq; +sequence<OneOptional*> OneOptionalPrxSeq; + +sequence<byte> Serializable; + +dictionary<int, int> IntIntDict; +dictionary<string, int> StringIntDict; +dictionary<int, MyEnum> IntEnumDict; +dictionary<int, FixedStruct> IntFixedStructDict; +dictionary<int, VarStruct> IntVarStructDict; +dictionary<int, OneOptional> IntOneOptionalDict; +dictionary<int, OneOptional*> IntOneOptionalPrxDict; + +class MultiOptional +{ + optional(1) byte a; + optional(2) bool b; + optional(3) short c; + optional(4) int d; + optional(5) long e; + optional(6) float f; + optional(7) double g; + optional(8) string h; + optional(9) MyEnum i; + optional(10) MultiOptional* j; + optional(11) MultiOptional k; + optional(12) ByteSeq bs; + optional(13) StringSeq ss; + optional(14) IntIntDict iid; + optional(15) StringIntDict sid; + optional(16) FixedStruct fs; + optional(17) VarStruct vs; + + optional(18) ShortSeq shs; + optional(19) MyEnumSeq es; + optional(20) FixedStructSeq fss; + optional(21) VarStructSeq vss; + optional(22) OneOptionalSeq oos; + optional(23) OneOptionalPrxSeq oops; + + optional(24) IntEnumDict ied; + optional(25) IntFixedStructDict ifsd; + optional(26) IntVarStructDict ivsd; + optional(27) IntOneOptionalDict iood; + optional(28) IntOneOptionalPrxDict ioopd; + + optional(29) BoolSeq bos; + + optional(30) Serializable ser; +}; + +class A +{ + int requiredA; + optional(1) int ma; + optional(50) int mb; + optional(500) int mc; +}; + +["preserve-slice"] +class B extends A +{ + int requiredB; + optional(10) int md; +}; + +class C extends B +{ + string ss; + optional(890) string ms; +}; + +class WD +{ + optional(1) int a = 5; + optional(2) string s = "test"; +}; + +exception OptionalException +{ + optional(1) int a = 5; + optional(2) string b; + optional(50) OneOptional o; +}; + +exception DerivedException extends OptionalException +{ + optional(600) string ss = "test"; + optional(601) OneOptional o2; +}; + +exception RequiredException extends OptionalException +{ + string ss = "test"; + OneOptional o2; +}; + +class OptionalWithCustom +{ + optional(1) SmallStructList l; + ["protected"] optional(2) SmallStructList lp; + optional(3) ClassVarStruct s; +}; + +["ami"] +class Initial +{ + void shutdown(); + + Object pingPong(Object o); + + void opOptionalException(optional(1) int a, optional(2) string b, optional(3) OneOptional o) + throws OptionalException; + + void opDerivedException(optional(1) int a, optional(2) string b, optional(3) OneOptional o) + throws OptionalException; + + void opRequiredException(optional(1) int a, optional(2) string b, optional(3) OneOptional o) + throws OptionalException; + + optional(1) byte opByte(optional(2) byte p1, out optional(3) byte p3); + + optional(1) bool opBool(optional(2) bool p1, out optional(3) bool p3); + + optional(1) short opShort(optional(2) short p1, out optional(3) short p3); + + optional(1) int opInt(optional(2) int p1, out optional(3) int p3); + + optional(3) long opLong(optional(1) long p1, out optional(2) long p3); + + optional(1) float opFloat(optional(2) float p1, out optional(3) float p3); + + optional(1) double opDouble(optional(2) double p1, out optional(3) double p3); + + optional(1) string opString(optional(2) string p1, out optional(3) string p3); + + optional(1) MyEnum opMyEnum(optional(2) MyEnum p1, out optional(3) MyEnum p3); + + optional(1) SmallStruct opSmallStruct(optional(2) SmallStruct p1, out optional(3) SmallStruct p3); + + optional(1) FixedStruct opFixedStruct(optional(2) FixedStruct p1, out optional(3) FixedStruct p3); + + optional(1) VarStruct opVarStruct(optional(2) VarStruct p1, out optional(3) VarStruct p3); + + optional(1) OneOptional opOneOptional(optional(2) OneOptional p1, out optional(3) OneOptional p3); + + optional(1) OneOptional* opOneOptionalProxy(optional(2) OneOptional* p1, out optional(3) OneOptional* p3); + + optional(1) ByteSeq opByteSeq(optional(2) ByteSeq p1, out optional(3) ByteSeq p3); + + optional(1) BoolSeq opBoolSeq(optional(2) BoolSeq p1, out optional(3) BoolSeq p3); + + optional(1) ShortSeq opShortSeq(optional(2) ShortSeq p1, out optional(3) ShortSeq p3); + + optional(1) IntSeq opIntSeq(optional(2) IntSeq p1, out optional(3) IntSeq p3); + + optional(1) LongSeq opLongSeq(optional(2) LongSeq p1, out optional(3) LongSeq p3); + + optional(1) FloatSeq opFloatSeq(optional(2) FloatSeq p1, out optional(3) FloatSeq p3); + + optional(1) DoubleSeq opDoubleSeq(optional(2) DoubleSeq p1, out optional(3) DoubleSeq p3); + + optional(1) StringSeq opStringSeq(optional(2) StringSeq p1, out optional(3) StringSeq p3); + + optional(1) SmallStructSeq opSmallStructSeq(optional(2) SmallStructSeq p1, out optional(3) SmallStructSeq p3); + + optional(1) SmallStructList opSmallStructList(optional(2) SmallStructList p1, out optional(3) SmallStructList p3); + + optional(1) FixedStructSeq opFixedStructSeq(optional(2) FixedStructSeq p1, out optional(3) FixedStructSeq p3); + + optional(1) FixedStructList opFixedStructList(optional(2) FixedStructList p1, out optional(3) FixedStructList p3); + + optional(1) VarStructSeq opVarStructSeq(optional(2) VarStructSeq p1, out optional(3) VarStructSeq p3); + + optional(1) IntIntDict opIntIntDict(optional(2) IntIntDict p1, out optional(3) IntIntDict p3); + + optional(1) StringIntDict opStringIntDict(optional(2) StringIntDict p1, out optional(3) StringIntDict p3); + + void opClassAndUnknownOptional(A p); + + bool supportsRequiredParams(); + + bool supportsJavaSerializable(); + + bool supportsCsharpSerializable(); +}; + +}; diff --git a/php/test/Ice/optional/run.py b/php/test/Ice/optional/run.py new file mode 100755 index 00000000000..13f58435db4 --- /dev/null +++ b/php/test/Ice/optional/run.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# ********************************************************************** +# +# Copyright (c) 2003-2012 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. +# +# ********************************************************************** + +import os, sys + +path = [ ".", "..", "../..", "../../..", "../../../..", "../../../../.." ] +head = os.path.dirname(sys.argv[0]) +if len(head) > 0: + path = [os.path.join(head, p) for p in path] +path = [os.path.abspath(p) for p in path if os.path.exists(os.path.join(p, "scripts", "TestUtil.py")) ] +if len(path) == 0: + raise RuntimeError("can't find toplevel directory!") +sys.path.append(os.path.join(path[0], "scripts")) +import TestUtil + +print("Running test with compact (default) format.") +TestUtil.clientServerTest() +print("Running test with sliced format.") +TestUtil.clientServerTest(additionalClientOptions="--Ice.Default.SlicedFormat", additionalServerOptions="--Ice.Default.SlicedFormat") diff --git a/php/test/Ice/slicing/objects/Client.php b/php/test/Ice/slicing/objects/Client.php index e57f3b44269..a2e817ef2ad 100644 --- a/php/test/Ice/slicing/objects/Client.php +++ b/php/test/Ice/slicing/objects/Client.php @@ -110,15 +110,24 @@ function allTests($communicator) echo "unknown with Object as Object... "; flush(); { + $usocls = $NS ? "Ice\\UnknownSlicedObject" : "Ice_UnknownSlicedObject"; try { $o = $test->SUnknownAsObject(); - test(false); + test($test->ice_getEncodingVersion() != $Ice_Encoding_1_0); + test($o instanceof $usocls); + test($o->unknownTypeId == "::Test::SUnknown"); + test($o->_ice_slicedData != null); + $test->checkSUnknown($o); } catch(Exception $b) { $excls = $NS ? "Ice\\NoObjectFactoryException" : "Ice_NoObjectFactoryException"; - if(!($b instanceof $excls)) + if($b instanceof $excls) + { + test($test->ice_getEncodingVersion() == $Ice_Encoding_1_0); + } + else { throw $ex; } diff --git a/php/test/Ice/slicing/objects/Test.ice b/php/test/Ice/slicing/objects/Test.ice index 8e20db55def..1272f947d8b 100644 --- a/php/test/Ice/slicing/objects/Test.ice +++ b/php/test/Ice/slicing/objects/Test.ice @@ -110,6 +110,7 @@ interface TestIntf ["format:compact"] SBase SBSUnknownDerivedAsSBaseCompact(); Object SUnknownAsObject(); + void checkSUnknown(Object o); B oneElementCycle(); B twoElementCycle(); diff --git a/py/modules/IcePy/Types.cpp b/py/modules/IcePy/Types.cpp index 20e7975753a..d2c1696b881 100644 --- a/py/modules/IcePy/Types.cpp +++ b/py/modules/IcePy/Types.cpp @@ -932,7 +932,7 @@ IcePy::EnumInfo::optionalFormat() const } void -IcePy::EnumInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*, bool, const Ice::StringSeq*) +IcePy::EnumInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap*, bool optional, const Ice::StringSeq*) { assert(PyObject_IsInstance(p, pythonType.get()) == 1); // validate() should have caught this. @@ -962,42 +962,15 @@ IcePy::EnumInfo::marshal(PyObject* p, const Ice::OutputStreamPtr& os, ObjectMap* throw AbortMarshaling(); } - if(count <= 127) - { - os->write(static_cast<Ice::Byte>(ival)); - } - else if(count <= 32767) - { - os->write(static_cast<Ice::Short>(ival)); - } - else - { - os->write(ival); - } + os->writeEnum(ival, count); } void IcePy::EnumInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, PyObject* target, void* closure, bool, const Ice::StringSeq*) { - Ice::Int val; Ice::Int count = static_cast<Ice::Int>(enumerators.size()); - if(count <= 127) - { - Ice::Byte b; - is->read(b); - val = b; - } - else if(count <= 32767) - { - Ice::Short sh; - is->read(sh); - val = sh; - } - else - { - is->read(val); - } + Ice::Int val = is->readEnum(count); if(val < 0 || val >= count) { @@ -2815,10 +2788,14 @@ IcePy::ClassInfo::printMembers(PyObject* value, IceUtilInternal::Output& out, Pr char* memberName = const_cast<char*>(member->name.c_str()); PyObjectHandle attr = PyObject_GetAttrString(value, memberName); out << nl << member->name << " = "; - if(!attr.get() || attr.get() == Unset) + if(!attr.get()) { out << "<not defined>"; } + else if(attr.get() == Unset) + { + out << "<unset>"; + } else { member->type->print(attr.get(), out, history); @@ -3404,7 +3381,9 @@ IcePy::ExceptionInfo::printMembers(PyObject* value, IceUtilInternal::Output& out base->printMembers(value, out, history); } - for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q) + DataMemberList::iterator q; + + for(q = members.begin(); q != members.end(); ++q) { DataMemberPtr member = *q; char* memberName = const_cast<char*>(member->name.c_str()); @@ -3419,6 +3398,26 @@ IcePy::ExceptionInfo::printMembers(PyObject* value, IceUtilInternal::Output& out member->type->print(attr.get(), out, history); } } + + for(q = optionalMembers.begin(); q != optionalMembers.end(); ++q) + { + DataMemberPtr member = *q; + char* memberName = const_cast<char*>(member->name.c_str()); + PyObjectHandle attr = PyObject_GetAttrString(value, memberName); + out << nl << member->name << " = "; + if(!attr.get()) + { + out << "<not defined>"; + } + else if(attr.get() == Unset) + { + out << "<unset>"; + } + else + { + member->type->print(attr.get(), out, history); + } + } } // diff --git a/rb/src/IceRuby/Types.cpp b/rb/src/IceRuby/Types.cpp index f23c6eb5a7b..4e1a1de95f9 100644 --- a/rb/src/IceRuby/Types.cpp +++ b/rb/src/IceRuby/Types.cpp @@ -756,49 +756,22 @@ IceRuby::EnumInfo::marshal(VALUE p, const Ice::OutputStreamPtr& os, ObjectMap*, // volatile VALUE val = callRuby(rb_iv_get, p, "@val"); assert(FIXNUM_P(val)); - long ival = FIX2LONG(val); - long count = static_cast<long>(enumerators.size()); + Ice::Int ival = static_cast<Ice::Int>(FIX2LONG(val)); + const Ice::Int count = static_cast<Ice::Int>(enumerators.size()); if(ival < 0 || ival >= count) { throw RubyException(rb_eRangeError, "value %ld is out of range for enum %s", ival, id.c_str()); } - if(count <= 127) - { - os->write(static_cast<Ice::Byte>(ival)); - } - else if(count <= 32767) - { - os->write(static_cast<Ice::Short>(ival)); - } - else - { - os->write(static_cast<Ice::Int>(ival)); - } + os->writeEnum(ival, count); } void IceRuby::EnumInfo::unmarshal(const Ice::InputStreamPtr& is, const UnmarshalCallbackPtr& cb, VALUE target, void* closure, bool) { - Ice::Int val; - Ice::Int count = static_cast<Ice::Int>(enumerators.size()); - if(count <= 127) - { - Ice::Byte b; - is->read(b); - val = b; - } - else if(count <= 32767) - { - Ice::Short sh; - is->read(sh); - val = sh; - } - else - { - is->read(val); - } + const Ice::Int count = static_cast<Ice::Int>(enumerators.size()); + Ice::Int val = is->readEnum(count); if(val < 0 || val >= count) { @@ -2098,7 +2071,9 @@ IceRuby::ClassInfo::printMembers(VALUE value, IceUtilInternal::Output& out, Prin base->printMembers(value, out, history); } - for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) + DataMemberList::const_iterator q; + + for(q = members.begin(); q != members.end(); ++q) { DataMemberPtr member = *q; out << nl << member->name << " = "; @@ -2112,6 +2087,28 @@ IceRuby::ClassInfo::printMembers(VALUE value, IceUtilInternal::Output& out, Prin member->type->print(val, out, history); } } + + for(q = optionalMembers.begin(); q != optionalMembers.end(); ++q) + { + DataMemberPtr member = *q; + out << nl << member->name << " = "; + if(callRuby(rb_ivar_defined, value, member->rubyID) == Qfalse) + { + out << "<not defined>"; + } + else + { + volatile VALUE val = callRuby(rb_ivar_get, value, member->rubyID); + if(val == Unset) + { + out << "<unset>"; + } + else + { + member->type->print(val, out, history); + } + } + } } bool @@ -2597,7 +2594,9 @@ IceRuby::ExceptionInfo::printMembers(VALUE value, IceUtilInternal::Output& out, base->printMembers(value, out, history); } - for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q) + DataMemberList::const_iterator q; + + for(q = members.begin(); q != members.end(); ++q) { DataMemberPtr member = *q; out << nl << member->name << " = "; @@ -2611,6 +2610,28 @@ IceRuby::ExceptionInfo::printMembers(VALUE value, IceUtilInternal::Output& out, member->type->print(val, out, history); } } + + for(q = optionalMembers.begin(); q != optionalMembers.end(); ++q) + { + DataMemberPtr member = *q; + out << nl << member->name << " = "; + if(callRuby(rb_ivar_defined, value, member->rubyID) == Qfalse) + { + out << "<not defined>"; + } + else + { + volatile VALUE val = callRuby(rb_ivar_get, value, member->rubyID); + if(val == Unset) + { + out << "<unset>"; + } + else + { + member->type->print(val, out, history); + } + } + } } // |