Пример #1
0
static void com_write_dimension(zval *object, zval *offset, zval *value)
{
	php_com_dotnet_object *obj;
	zval args[2];
	VARIANT v;
	HRESULT res;

	obj = CDNO_FETCH(object);

	if (V_VT(&obj->v) == VT_DISPATCH) {
		ZVAL_COPY_VALUE(&args[0], offset);
		ZVAL_COPY_VALUE(&args[1], value);

		VariantInit(&v);

		if (SUCCESS == php_com_do_invoke_by_id(obj, DISPID_VALUE,
				DISPATCH_METHOD|DISPATCH_PROPERTYPUT, &v, 2, args, 0, 0)) {
			VariantClear(&v);
		}
	} else if (V_ISARRAY(&obj->v)) {
		LONG indices = 0;
		VARTYPE vt;

		if (SafeArrayGetDim(V_ARRAY(&obj->v)) == 1) {
			if (FAILED(SafeArrayGetVartype(V_ARRAY(&obj->v), &vt)) || vt == VT_EMPTY) {
				vt = V_VT(&obj->v) & ~VT_ARRAY;
			}

			convert_to_long(offset);
			indices = (LONG)Z_LVAL_P(offset);

			VariantInit(&v);
			php_com_variant_from_zval(&v, value, obj->code_page);

			if (V_VT(&v) != vt) {
				VariantChangeType(&v, &v, 0, vt);
			}

			if (vt == VT_VARIANT) {
				res = SafeArrayPutElement(V_ARRAY(&obj->v), &indices, &v);
			} else {
				res = SafeArrayPutElement(V_ARRAY(&obj->v), &indices, &v.lVal);
			}

			VariantClear(&v);

			if (FAILED(res)) {
				php_com_throw_exception(res, NULL);
			}

		} else {
			php_com_throw_exception(DISP_E_BADINDEX, "this variant has multiple dimensions; you can't set a new value without specifying *all* dimensions");
		}

	} else {
		php_com_throw_exception(E_INVALIDARG, "this variant is not an array type");
	}
}
Пример #2
0
static void variant_unary_operation(enum variant_unary_opcode op, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
{
	VARIANT vres;
	VARIANT left_val;
	VARIANT *vleft = NULL;
	zval *zleft = NULL;
	php_com_dotnet_object *obj;
	HRESULT result;
	int codepage = CP_ACP;

	VariantInit(&left_val);
	VariantInit(&vres);

	if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
			ZEND_NUM_ARGS(), "O", &zleft, php_com_variant_class_entry)) {
		obj = CDNO_FETCH(zleft);
		vleft = &obj->v;
	} else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(),
			"z!", &zleft)) {
		vleft = &left_val;
		php_com_variant_from_zval(vleft, zleft, codepage);
	} else {
		return;
	}

	switch (op) {
		case VOP_ABS:
			result = VarAbs(vleft, &vres);
			break;
		case VOP_FIX:
			result = VarFix(vleft, &vres);
			break;
		case VOP_INT:
			result = VarInt(vleft, &vres);
			break;
		case VOP_NEG:
			result = VarNeg(vleft, &vres);
			break;
		case VOP_NOT:
			result = VarNot(vleft, &vres);
			break;
		default:
			result = E_INVALIDARG;
	}

	if (SUCCEEDED(result)) {
		php_com_wrap_variant(return_value, &vres, codepage);
	} else {
		php_com_throw_exception(result, NULL);
	}

	VariantClear(&vres);
	VariantClear(&left_val);
}
Пример #3
0
int php_com_do_invoke_by_id(php_com_dotnet_object *obj, DISPID dispid,
		WORD flags,	VARIANT *v, int nargs, zval *args, int silent, int allow_noarg)
{
	DISPID altdispid;
	DISPPARAMS disp_params;
	HRESULT hr;
	VARIANT *vargs = NULL;
	int i;

	if (nargs) {
		vargs = (VARIANT*)safe_emalloc(sizeof(VARIANT), nargs, 0);
	}

	/* Invoke'd args are in reverse order */
	for (i = 0; i < nargs; i++) {
		php_com_variant_from_zval(&vargs[i], &args[nargs - i - 1], obj->code_page);
	}

	disp_params.cArgs = nargs;
	disp_params.cNamedArgs = 0;
	disp_params.rgvarg = vargs;
	disp_params.rgdispidNamedArgs = NULL;

	if (flags & DISPATCH_PROPERTYPUT) {
		altdispid = DISPID_PROPERTYPUT;
		disp_params.rgdispidNamedArgs = &altdispid;
		disp_params.cNamedArgs = 1;
	}

	/* this will create an exception if needed */
	hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v, silent, allow_noarg);	

	/* release variants */
	if (vargs) {
		for (i = 0; i < nargs; i++) {
			VariantClear(&vargs[i]);
		}
		efree(vargs);
	}

	/* a bit of a hack this, but it's needed for COM array access. */
	if (hr == DISP_E_BADPARAMCOUNT)
		return hr;
	
	return SUCCEEDED(hr) ? SUCCESS : FAILURE;
}
Пример #4
0
/* create an automation SafeArray from a PHP array.
 * Only creates a single-dimensional array of variants.
 * The keys of the PHP hash MUST be numeric.  If the array
 * is sparse, then the gaps will be filled with NULL variants */
static void safe_array_from_zval(VARIANT *v, zval *z, int codepage TSRMLS_DC)
{
	SAFEARRAY *sa = NULL;
	SAFEARRAYBOUND bound;
	HashPosition pos;
	int keytype;
	char *strindex;
	int strindexlen;
	long intindex = -1;
	long max_index = 0;
	VARIANT *va;
	zval **item;
		
	/* find the largest array index, and assert that all keys are integers */
	zend_hash_internal_pointer_reset_ex(HASH_OF(z), &pos);
	for (;; zend_hash_move_forward_ex(HASH_OF(z), &pos)) {

		keytype = zend_hash_get_current_key_ex(HASH_OF(z), &strindex, &strindexlen, &intindex, 0, &pos);

		if (HASH_KEY_IS_STRING == keytype) {
			goto bogus;
		} else if (HASH_KEY_NON_EXISTANT == keytype) {
			break;
		}
		if (intindex > max_index) {
			max_index = intindex;
		}
	}

	/* allocate the structure */	
	bound.lLbound = 0;
	bound.cElements = intindex + 1;
	sa = SafeArrayCreate(VT_VARIANT, 1, &bound);

	/* get a lock on the array itself */
	SafeArrayAccessData(sa, &va);
	va = (VARIANT*)sa->pvData;
	
	/* now fill it in */
	zend_hash_internal_pointer_reset_ex(HASH_OF(z), &pos);
	for (;; zend_hash_move_forward_ex(HASH_OF(z), &pos)) {
		if (FAILURE == zend_hash_get_current_data_ex(HASH_OF(z), (void**)&item, &pos)) {
			break;
		}
		zend_hash_get_current_key_ex(HASH_OF(z), &strindex, &strindexlen, &intindex, 0, &pos);
		php_com_variant_from_zval(&va[intindex], *item, codepage TSRMLS_CC);		
	}

	/* Unlock it and stuff it into our variant */
	SafeArrayUnaccessData(sa);
	V_VT(v) = VT_ARRAY|VT_VARIANT;
	V_ARRAY(v) = sa;

	return;

bogus:
	php_error_docref(NULL TSRMLS_CC, E_WARNING, "COM: converting from PHP array to VARIANT array; only arrays with numeric keys are allowed");

	V_VT(v) = VT_NULL;

	if (sa) {
		SafeArrayUnlock(sa);
		SafeArrayDestroy(sa);
	}
}
Пример #5
0
/* the core of COM */
int php_com_do_invoke_byref(php_com_dotnet_object *obj, zend_internal_function *f,
		WORD flags,	VARIANT *v, int nargs, zval *args)
{
	DISPID dispid, altdispid;
	DISPPARAMS disp_params;
	HRESULT hr;
	VARIANT *vargs = NULL, *byref_vals = NULL;
	int i, byref_count = 0, j;

	/* assumption: that the active function (f) is the function we generated for the engine */
	if (!f) {
		return FAILURE;
	}
	
	hr = php_com_get_id_of_name(obj, f->function_name->val, f->function_name->len, &dispid);

	if (FAILED(hr)) {
		char *winerr = NULL;
		char *msg = NULL;
		winerr = php_win32_error_to_msg(hr);
		spprintf(&msg, 0, "Unable to lookup `%s': %s", f->function_name->val, winerr);
		LocalFree(winerr);
		php_com_throw_exception(hr, msg);
		efree(msg);
		return FAILURE;
	}


	if (nargs) {
		vargs = (VARIANT*)safe_emalloc(sizeof(VARIANT), nargs, 0);
	}

	if (f->arg_info) {
		for (i = 0; i < nargs; i++) {
			if (f->arg_info[nargs - i - 1].pass_by_reference) {
				byref_count++;
			}
		}
	}

	if (byref_count) {
		byref_vals = (VARIANT*)safe_emalloc(sizeof(VARIANT), byref_count, 0);
		for (j = 0, i = 0; i < nargs; i++) {
			if (f->arg_info[nargs - i - 1].pass_by_reference) {
				/* put the value into byref_vals instead */
				php_com_variant_from_zval(&byref_vals[j], &args[nargs - i - 1], obj->code_page);

				/* if it is already byref, "move" it into the vargs array, otherwise
				 * make vargs a reference to this value */
				if (V_VT(&byref_vals[j]) & VT_BYREF) {
					memcpy(&vargs[i], &byref_vals[j], sizeof(vargs[i]));
					VariantInit(&byref_vals[j]); /* leave the variant slot empty to simplify cleanup */
				} else {
					VariantInit(&vargs[i]);
					V_VT(&vargs[i]) = V_VT(&byref_vals[j]) | VT_BYREF;
					/* union magic ensures that this works out */
					vargs[i].byref = &V_UINT(&byref_vals[j]);
				}
				j++;
			} else {
				php_com_variant_from_zval(&vargs[i], &args[nargs - i - 1], obj->code_page);
			}
		}
		
	} else {
		/* Invoke'd args are in reverse order */
		for (i = 0; i < nargs; i++) {
			php_com_variant_from_zval(&vargs[i], &args[nargs - i - 1], obj->code_page);
		}
	}

	disp_params.cArgs = nargs;
	disp_params.cNamedArgs = 0;
	disp_params.rgvarg = vargs;
	disp_params.rgdispidNamedArgs = NULL;

	if (flags & DISPATCH_PROPERTYPUT) {
		altdispid = DISPID_PROPERTYPUT;
		disp_params.rgdispidNamedArgs = &altdispid;
		disp_params.cNamedArgs = 1;
	}

	/* this will create an exception if needed */
	hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v, 0, 0);	

	/* release variants */
	if (vargs) {
		if (f && f->arg_info) {
			for (i = 0, j = 0; i < nargs; i++) {
				/* if this was byref, update the zval */
				if (f->arg_info[nargs - i - 1].pass_by_reference) {
					SEPARATE_ZVAL_IF_NOT_REF(&args[nargs - i - 1]);

					/* if the variant is pointing at the byref_vals, we need to map
					 * the pointee value as a zval; otherwise, the value is pointing
					 * into an existing PHP variant record */
					if (V_VT(&vargs[i]) & VT_BYREF) {
						if (vargs[i].byref == &V_UINT(&byref_vals[j])) {
							/* copy that value */
							php_com_zval_from_variant(&args[nargs - i - 1], &byref_vals[j],
								obj->code_page);
						}
					} else {
						/* not sure if this can ever happen; the variant we marked as BYREF
						 * is no longer BYREF - copy its value */
						php_com_zval_from_variant(&args[nargs - i - 1], &vargs[i],
							obj->code_page);
					}
					VariantClear(&byref_vals[j]);
					j++;
				}
				VariantClear(&vargs[i]);
			}
		} else {
			for (i = 0, j = 0; i < nargs; i++) {
				VariantClear(&vargs[i]);
			}
		}
		efree(vargs);
	}

	return SUCCEEDED(hr) ? SUCCESS : FAILURE;
}
Пример #6
0
static void saproxy_write_dimension(zend_object *object, zval *offset, zval *value)
{
	php_com_saproxy *proxy = (php_com_saproxy*) object;
	UINT dims, i;
	HRESULT res;
	VARIANT v;

	if (V_VT(&proxy->obj->v) == VT_DISPATCH) {
		/* We do a prop-set using the first dimension as the property name,
		 * all subsequent dimensions and offset as parameters, with value as
		 * the final value */
		zval *args = safe_emalloc(proxy->dimensions + 2, sizeof(zval), 0);

		for (i = 1; i < (UINT) proxy->dimensions; i++) {
			ZVAL_COPY_VALUE(&args[i-1], &proxy->indices[i]);
		}
		ZVAL_COPY_VALUE(&args[i-1], offset);
		ZVAL_COPY_VALUE(&args[i], value);

		convert_to_string(&proxy->indices[0]);
		VariantInit(&v);
		if (SUCCESS == php_com_do_invoke(proxy->obj, Z_STRVAL(proxy->indices[0]),
					Z_STRLEN(proxy->indices[0]), DISPATCH_PROPERTYPUT, &v, proxy->dimensions + 1,
					args, 0)) {
			VariantClear(&v);
		}

		efree(args);

	} else if (V_ISARRAY(&proxy->obj->v)) {
		LONG *indices;
		VARTYPE vt;

		dims = SafeArrayGetDim(V_ARRAY(&proxy->obj->v));
		indices = safe_emalloc(dims, sizeof(LONG), 0);
		/* copy indices from proxy */
		for (i = 0; i < dims; i++) {
			convert_to_long(&proxy->indices[i]);
			indices[i] = (LONG)Z_LVAL(proxy->indices[i]);
		}

		/* add user-supplied index */
		convert_to_long(offset);
		indices[dims-1] = (LONG)Z_LVAL_P(offset);

		if (FAILED(SafeArrayGetVartype(V_ARRAY(&proxy->obj->v), &vt)) || vt == VT_EMPTY) {
			vt = V_VT(&proxy->obj->v) & ~VT_ARRAY;
		}

		VariantInit(&v);
		php_com_variant_from_zval(&v, value, proxy->obj->code_page);

		if (V_VT(&v) != vt) {
			VariantChangeType(&v, &v, 0, vt);
		}

		if (vt == VT_VARIANT) {
			res = SafeArrayPutElement(V_ARRAY(&proxy->obj->v), indices, &v);
		} else {
			res = SafeArrayPutElement(V_ARRAY(&proxy->obj->v), indices, &v.lVal);
		}

		efree(indices);
		VariantClear(&v);

		if (FAILED(res)) {
			php_com_throw_exception(res, NULL);
		}
	} else {
		php_com_throw_exception(E_NOTIMPL, "invalid write to com proxy object");
	}
}
Пример #7
0
static void variant_binary_operation(enum variant_binary_opcode op, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
{
	VARIANT vres;
	VARIANT left_val, right_val;
	VARIANT *vleft = NULL, *vright = NULL;
	zval *zleft = NULL, *zright = NULL;
	php_com_dotnet_object *obj;
	HRESULT result;
	int codepage = CP_ACP;

	VariantInit(&left_val);
	VariantInit(&right_val);
	VariantInit(&vres);

	if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
			ZEND_NUM_ARGS(), "OO", &zleft, php_com_variant_class_entry,
			&zright, php_com_variant_class_entry)) {
		obj = CDNO_FETCH(zleft);
		vleft = &obj->v;
		obj = CDNO_FETCH(zright);
		vright = &obj->v;
	} else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
			ZEND_NUM_ARGS(), "Oz!", &zleft, php_com_variant_class_entry,
			&zright)) {
		obj = CDNO_FETCH(zleft);
		vleft = &obj->v;
		vright = &right_val;
		php_com_variant_from_zval(vright, zright, codepage);
	} else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
			ZEND_NUM_ARGS(), "z!O", &zleft, &zright, php_com_variant_class_entry)) {
		obj = CDNO_FETCH(zright);
		vright = &obj->v;
		vleft = &left_val;
		php_com_variant_from_zval(vleft, zleft, codepage);
	} else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(),
			"z!z!", &zleft, &zright)) {

		vleft = &left_val;
		php_com_variant_from_zval(vleft, zleft, codepage);

		vright = &right_val;
		php_com_variant_from_zval(vright, zright, codepage);

	} else {
		return;
	}

	switch (op) {
		case VOP_ADD:
			result = VarAdd(vleft, vright, &vres);
			break;
		case VOP_CAT:
			result = VarCat(vleft, vright, &vres);
			break;
		case VOP_SUB:
			result = VarSub(vleft, vright, &vres);
			break;
		case VOP_MUL:
			result = VarMul(vleft, vright, &vres);
			break;
		case VOP_AND:
			result = VarAnd(vleft, vright, &vres);
			break;
		case VOP_DIV:
			result = VarDiv(vleft, vright, &vres);
			break;
		case VOP_EQV:
			result = VarEqv(vleft, vright, &vres);
			break;
		case VOP_IDIV:
			result = VarIdiv(vleft, vright, &vres);
			break;
		case VOP_IMP:
			result = VarImp(vleft, vright, &vres);
			break;
		case VOP_MOD:
			result = VarMod(vleft, vright, &vres);
			break;
		case VOP_OR:
			result = VarOr(vleft, vright, &vres);
			break;
		case VOP_POW:
			result = VarPow(vleft, vright, &vres);
			break;
		case VOP_XOR:
			result = VarXor(vleft, vright, &vres);
			break;
		/*Let say it fails as no valid op has been given */
		default:
			result = E_INVALIDARG;
	}

	if (SUCCEEDED(result)) {
		php_com_wrap_variant(return_value, &vres, codepage);
	} else {
		php_com_throw_exception(result, NULL);
	}

	VariantClear(&vres);
	VariantClear(&left_val);
	VariantClear(&right_val);
}
Пример #8
0
/* create an automation SafeArray from a PHP array.
 * Only creates a single-dimensional array of variants.
 * The keys of the PHP hash MUST be numeric.  If the array
 * is sparse, then the gaps will be filled with NULL variants */
static void safe_array_from_zval(VARIANT *v, zval *z, int codepage)
{
	SAFEARRAY *sa = NULL;
	SAFEARRAYBOUND bound;
	HashPosition pos;
	int keytype;
	zend_string *strindex;
	zend_ulong intindex = 0;
	VARIANT *va;
	zval *item;

	/* find the largest array index, and assert that all keys are integers */
	zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(z), &pos);
	for (;; zend_hash_move_forward_ex(Z_ARRVAL_P(z), &pos)) {

		keytype = zend_hash_get_current_key_ex(Z_ARRVAL_P(z), &strindex, &intindex, &pos);

		if (HASH_KEY_IS_STRING == keytype) {
			goto bogus;
		} else if (HASH_KEY_NON_EXISTENT == keytype) {
			break;
		} else if (intindex > UINT_MAX) {
			php_error_docref(NULL, E_WARNING, "COM: max number %u of elements in safe array exceeded", UINT_MAX);
			break;
		}
	}

	/* allocate the structure */
	bound.lLbound = 0;
	bound.cElements = zend_hash_num_elements(Z_ARRVAL_P(z));
	sa = SafeArrayCreate(VT_VARIANT, 1, &bound);

	/* get a lock on the array itself */
	SafeArrayAccessData(sa, &va);
	va = (VARIANT*)sa->pvData;

	/* now fill it in */
	zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(z), &pos);
	for (;; zend_hash_move_forward_ex(Z_ARRVAL_P(z), &pos)) {
		if (NULL == (item = zend_hash_get_current_data_ex(Z_ARRVAL_P(z), &pos))) {
			break;
		}
		zend_hash_get_current_key_ex(Z_ARRVAL_P(z), &strindex, &intindex, &pos);
		php_com_variant_from_zval(&va[intindex], item, codepage);
	}

	/* Unlock it and stuff it into our variant */
	SafeArrayUnaccessData(sa);
	V_VT(v) = VT_ARRAY|VT_VARIANT;
	V_ARRAY(v) = sa;

	return;

bogus:
	php_error_docref(NULL, E_WARNING, "COM: converting from PHP array to VARIANT array; only arrays with numeric keys are allowed");

	V_VT(v) = VT_NULL;

	if (sa) {
		SafeArrayUnlock(sa);
		SafeArrayDestroy(sa);
	}
}