TYPEMAP
UA_Boolean				T_PACKED
UA_SByte				T_PACKED
UA_Byte					T_PACKED
UA_Int16				T_PACKED
UA_UInt16				T_PACKED
UA_Int32				T_PACKED
UA_UInt32				T_PACKED
OPCUA_Open62541_UInt32			T_PTROBJ_OPTIONAL
# XXX this only works for Perl on 64 bit platforms
UA_Int64				T_PACKED
UA_UInt64				T_PACKED
UA_Float				T_PACKED
UA_Double				T_PACKED
UA_StatusCode				T_PACKED
UA_String				T_PACKED
UA_Guid					T_PACKED
UA_ByteString				T_PACKED
OPCUA_Open62541_NodeIdType		T_ENUM
UA_NodeId				T_PACKED
UA_BrowseRequest			T_PACKED
UA_BrowseResponse			T_PACKED
OPCUA_Open62541_NodeId			T_PTROBJ_OPTIONAL
OPCUA_Open62541_LocalizedText		T_PTROBJ_REFERENCE
UA_QualifiedName			T_PACKED
OPCUA_Open62541_DataType		T_PACKED
OPCUA_Open62541_Variant			T_PTROBJ_REFERENCE
UA_VariableAttributes			T_PACKED
OPCUA_Open62541_Server			T_PTROBJ_SPECIAL
OPCUA_Open62541_ServerConfig		T_PTROBJ_SPECIAL
OPCUA_Open62541_Client			T_PTROBJ_SPECIAL
OPCUA_Open62541_ClientConfig		T_PTROBJ_SPECIAL
OPCUA_Open62541_ClientState		T_ENUM
OPCUA_Open62541_BrowseResultMask	T_ENUM

#############################################################################
INPUT
T_PTROBJ_OPTIONAL
	if (!SvOK($arg)) {
		/* Argument is optional, do not output anything if undef. */
		$var = NULL;
	} else if (SvROK($arg) && sv_derived_from($arg,
	    \"${(my $ntt=${ntype})=~s/_/::/g;\$ntt}\")) {
		/* Already an object pointer. */
		$var = INT2PTR($type, SvIV(SvRV($arg)));
	} else if (SvROK($arg) && SvTYPE(SvRV($arg)) < SVt_PVAV) {
		/* Scalar reference, set referenced variable to pointer. */
		$var = UA_${(my $ntt=${ntype})=~s/.*_//g;\$ntt}_new();
		if ($var == NULL)
			croak(\"UA_${(my $ntt=${ntype})=~s/.*_//g;\$ntt}_new\");
		DPRINTF(\"${(my $ntt=lc(${ntype}))=~s/.*_//g;\$ntt} %p\", $var);
		sv_setref_pv(SvRV($arg),
		    \"${(my $ntt=${ntype})=~s/_/::/g;\$ntt}\", $var);
	} else {
		croak(\"%s: %s is not a scalar reference\",
		    ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, \"$var\");
	}
T_PTROBJ_REFERENCE
	if (SvROK($arg) && sv_derived_from($arg,
	    \"${(my $ntt=${ntype})=~s/_/::/g;\$ntt}\")) {
		/* Already an object pointer. */
		$var = INT2PTR($type, SvIV(SvRV($arg)));
	} else if (SvROK($arg) && SvTYPE(SvRV($arg)) < SVt_PVAV) {
		/* Scalar reference, set referenced variable to pointer. */
		$var = UA_${(my $ntt=${ntype})=~s/.*_//g;\$ntt}_new();
		if ($var == NULL)
			croak(\"UA_${(my $ntt=${ntype})=~s/.*_//g;\$ntt}_new\");
		DPRINTF(\"${(my $ntt=lc(${ntype}))=~s/.*_//g;\$ntt} %p\", $var);
		sv_setref_pv(SvRV($arg),
		    \"${(my $ntt=${ntype})=~s/_/::/g;\$ntt}\", $var);
	} else {
		croak(\"%s: %s is not a scalar reference\",
		    ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, \"$var\");
	}
T_PTROBJ_SPECIAL
	if (SvROK($arg) && sv_derived_from($arg,
	    \"${(my $ntt=${ntype})=~s/_/::/g;\$ntt}\")) {
		$var = INT2PTR($type, SvIV((SV*)SvRV($arg)));
	} else {
		croak(\"%s: %s is not of type %s\",
		    ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]},
		    \"$var\", \"${(my $ntt=${ntype})=~s/_/::/g;\$ntt}\");
		/* NOTREACHED, but cppcheck does not know this. */
		exit(255);
	}

#############################################################################
OUTPUT
T_PTROBJ_REFERENCE
	sv_setref_pv($arg, \"${(my $ntt=${ntype})=~s/_/::/g;\$ntt}\", $var);
T_PTROBJ_SPECIAL
	sv_setref_pv($arg, \"${(my $ntt=${ntype})=~s/_/::/g;\$ntt}\", $var);
