xref: /PHP-8.2/ext/com_dotnet/com_misc.c (revision a01dd9fe)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Author: Wez Furlong  <wez@thebrainroom.com>                          |
14    +----------------------------------------------------------------------+
15  */
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include "php.h"
22 #include "php_ini.h"
23 #include "ext/standard/info.h"
24 #include "php_com_dotnet.h"
25 #include "php_com_dotnet_internal.h"
26 #include "Zend/zend_exceptions.h"
27 
php_com_throw_exception(HRESULT code,char * message)28 void php_com_throw_exception(HRESULT code, char *message)
29 {
30 	int free_msg = 0;
31 	if (message == NULL) {
32 		message = php_win32_error_to_msg(code);
33 		free_msg = 1;
34 	}
35 #if SIZEOF_ZEND_LONG == 8
36 	zend_throw_exception(php_com_exception_class_entry, message, (zend_long)(uint32_t)code);
37 #else
38 	zend_throw_exception(php_com_exception_class_entry, message, (zend_long)code);
39 #endif
40 	if (free_msg) {
41 		php_win32_error_msg_free(message);
42 	}
43 }
44 
php_com_wrap_dispatch(zval * z,IDispatch * disp,int codepage)45 PHP_COM_DOTNET_API void php_com_wrap_dispatch(zval *z, IDispatch *disp,
46 		int codepage)
47 {
48 	php_com_dotnet_object *obj;
49 
50 	obj = emalloc(sizeof(*obj));
51 	memset(obj, 0, sizeof(*obj));
52 	obj->code_page = codepage;
53 	obj->ce = php_com_variant_class_entry;
54 	obj->zo.ce = php_com_variant_class_entry;
55 
56 	VariantInit(&obj->v);
57 	V_VT(&obj->v) = VT_DISPATCH;
58 	V_DISPATCH(&obj->v) = disp;
59 
60 	IDispatch_AddRef(V_DISPATCH(&obj->v));
61 	IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &obj->typeinfo);
62 
63 	zend_object_std_init(&obj->zo, php_com_variant_class_entry);
64 	obj->zo.handlers = &php_com_object_handlers;
65 	ZVAL_OBJ(z, &obj->zo);
66 }
67 
php_com_wrap_variant(zval * z,VARIANT * v,int codepage)68 PHP_COM_DOTNET_API void php_com_wrap_variant(zval *z, VARIANT *v,
69 		int codepage)
70 {
71 	php_com_dotnet_object *obj;
72 
73 	obj = emalloc(sizeof(*obj));
74 	memset(obj, 0, sizeof(*obj));
75 	obj->code_page = codepage;
76 	obj->ce = php_com_variant_class_entry;
77 	obj->zo.ce = php_com_variant_class_entry;
78 
79 	VariantInit(&obj->v);
80 	VariantCopyInd(&obj->v, v);
81 	obj->modified = 0;
82 
83 	if ((V_VT(&obj->v) == VT_DISPATCH) && (V_DISPATCH(&obj->v) != NULL)) {
84 		IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &obj->typeinfo);
85 	}
86 
87 	zend_object_std_init(&obj->zo, php_com_variant_class_entry);
88 	obj->zo.handlers = &php_com_object_handlers;
89 	ZVAL_OBJ(z, &obj->zo);
90 }
91 
92 /* this is a convenience function for fetching a particular
93  * element from a (possibly multi-dimensional) safe array */
php_com_safearray_get_elem(VARIANT * array,VARIANT * dest,LONG dim1)94 PHP_COM_DOTNET_API bool php_com_safearray_get_elem(VARIANT *array, VARIANT *dest, LONG dim1)
95 {
96 	UINT dims;
97 	LONG lbound, ubound;
98 	LONG indices[1];
99 	VARTYPE vt;
100 
101 	if (!V_ISARRAY(array)) {
102 		return 0;
103 	}
104 
105 	dims = SafeArrayGetDim(V_ARRAY(array));
106 
107 	if (dims != 1) {
108 		/* TODO Promote to ValueError? */
109 		php_error_docref(NULL, E_WARNING,
110 			   "Can only handle single dimension variant arrays (this array has %d)", dims);
111 		return 0;
112 	}
113 
114 	if (FAILED(SafeArrayGetVartype(V_ARRAY(array), &vt)) || vt == VT_EMPTY) {
115 		vt = V_VT(array) & ~VT_ARRAY;
116 	}
117 
118 	/* determine the bounds */
119 	SafeArrayGetLBound(V_ARRAY(array), 1, &lbound);
120 	SafeArrayGetUBound(V_ARRAY(array), 1, &ubound);
121 
122 	/* check bounds */
123 	if (dim1 < lbound || dim1 > ubound) {
124 		php_com_throw_exception(DISP_E_BADINDEX, "index out of bounds");
125 		return 0;
126 	}
127 
128 	/* now fetch that element */
129 	VariantInit(dest);
130 
131 	indices[0] = dim1;
132 
133 	if (vt == VT_VARIANT) {
134 		SafeArrayGetElement(V_ARRAY(array), indices, dest);
135 	} else {
136 		V_VT(dest) = vt;
137 		/* store the value into "lVal" member of the variant.
138 		 * This works because it is a union; since we know the variant
139 		 * type, we end up with a working variant */
140 		SafeArrayGetElement(V_ARRAY(array), indices, &dest->lVal);
141 	}
142 
143 	return 1;
144 }
145