Skip to content

Commit 86e7e5d

Browse files
committed
ext/com_dotnet: Use modern HashTable APIs
1 parent 1331a61 commit 86e7e5d

File tree

2 files changed

+55
-115
lines changed

2 files changed

+55
-115
lines changed

ext/com_dotnet/com_variant.c

+23-42
Original file line numberDiff line numberDiff line change
@@ -24,73 +24,54 @@
2424
#include "php_com_dotnet.h"
2525
#include "php_com_dotnet_internal.h"
2626

27-
/* create an automation SafeArray from a PHP array.
27+
/* create an automation SafeArray from a PHP array (HashTable).
2828
* Only creates a single-dimensional array of variants.
2929
* The keys of the PHP hash MUST be numeric. */
30-
static void safe_array_from_zval(VARIANT *v, zval *z, int codepage)
30+
static void safe_array_from_hashtable(VARIANT *v, HashTable *ht, int codepage)
3131
{
3232
SAFEARRAY *sa = NULL;
3333
SAFEARRAYBOUND bound;
34-
HashPosition pos;
35-
int keytype;
36-
zend_string *strindex;
37-
zend_ulong intindex = 0;
3834
VARIANT *va;
39-
zval *item;
4035

4136
/* find the largest array index, and assert that all keys are integers */
42-
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(z), &pos);
43-
for (;; zend_hash_move_forward_ex(Z_ARRVAL_P(z), &pos)) {
44-
45-
keytype = zend_hash_get_current_key_ex(Z_ARRVAL_P(z), &strindex, &intindex, &pos);
37+
if (!zend_array_is_list(ht)) {
38+
// TODO: Make this a ValueError
39+
php_error_docref(NULL, E_WARNING, "COM: converting from PHP array to VARIANT array; only arrays with numeric keys are allowed");
40+
V_VT(v) = VT_NULL;
41+
return;
42+
}
43+
// TODO: Check not empty?
4644

47-
if (HASH_KEY_IS_STRING == keytype) {
48-
goto bogus;
49-
} else if (HASH_KEY_NON_EXISTENT == keytype) {
50-
break;
51-
} else if (intindex > UINT_MAX) {
52-
php_error_docref(NULL, E_WARNING, "COM: max number %u of elements in safe array exceeded", UINT_MAX);
53-
break;
54-
}
45+
uint32_t nb_values = zend_hash_num_elements(ht);
46+
if (nb_values > UINT_MAX) {
47+
// TODO: Make this a ValueError?
48+
php_error_docref(NULL, E_WARNING, "COM: max number %u of elements in safe array exceeded", UINT_MAX);
49+
V_VT(v) = VT_NULL;
50+
return;
5551
}
5652

5753
/* allocate the structure */
5854
bound.lLbound = 0;
59-
bound.cElements = zend_hash_num_elements(Z_ARRVAL_P(z));
55+
bound.cElements = nb_values;
6056
sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
6157

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

6662
/* now fill it in */
67-
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(z), &pos);
68-
for (;; zend_hash_move_forward_ex(Z_ARRVAL_P(z), &pos)) {
69-
if (NULL == (item = zend_hash_get_current_data_ex(Z_ARRVAL_P(z), &pos))) {
70-
break;
63+
zend_ulong index = 0;
64+
zval *value;
65+
ZEND_HASH_FOREACH_NUM_KEY_VAL(ht, index, value) {
66+
if (index < bound.cElements) {
67+
php_com_variant_from_zval(&va[index], value, codepage);
7168
}
72-
zend_hash_get_current_key_ex(Z_ARRVAL_P(z), &strindex, &intindex, &pos);
73-
if (intindex < bound.cElements) {
74-
php_com_variant_from_zval(&va[intindex], item, codepage);
75-
}
76-
}
69+
} ZEND_HASH_FOREACH_END();
7770

7871
/* Unlock it and stuff it into our variant */
7972
SafeArrayUnaccessData(sa);
8073
V_VT(v) = VT_ARRAY|VT_VARIANT;
8174
V_ARRAY(v) = sa;
82-
83-
return;
84-
85-
bogus:
86-
php_error_docref(NULL, E_WARNING, "COM: converting from PHP array to VARIANT array; only arrays with numeric keys are allowed");
87-
88-
V_VT(v) = VT_NULL;
89-
90-
if (sa) {
91-
SafeArrayUnlock(sa);
92-
SafeArrayDestroy(sa);
93-
}
9475
}
9576

9677
static void php_com_variant_from_zval_ex(VARIANT *v, zval *z, int codepage, VARTYPE vt)
@@ -142,7 +123,7 @@ static void php_com_variant_from_zval_ex(VARIANT *v, zval *z, int codepage, VART
142123

143124
case IS_ARRAY:
144125
/* map as safe array */
145-
safe_array_from_zval(v, z, codepage);
126+
safe_array_from_hashtable(v, Z_ARRVAL_P(z), codepage);
146127
break;
147128

148129
case IS_LONG:

ext/com_dotnet/com_wrapper.c

+32-73
Original file line numberDiff line numberDiff line change
@@ -420,10 +420,8 @@ static struct IDispatchExVtbl php_dispatch_vtbl = {
420420
* dispatch ids */
421421
static void generate_dispids(php_dispatchex *disp)
422422
{
423-
HashPosition pos;
424423
zend_string *name = NULL;
425-
zval *tmp, tmp2;
426-
int keytype;
424+
zval tmp;
427425
zend_long pid;
428426

429427
if (disp->dispid_to_name == NULL) {
@@ -435,71 +433,42 @@ static void generate_dispids(php_dispatchex *disp)
435433

436434
/* properties */
437435
if (Z_OBJPROP(disp->object)) {
438-
zend_hash_internal_pointer_reset_ex(Z_OBJPROP(disp->object), &pos);
439-
while (HASH_KEY_NON_EXISTENT != (keytype =
440-
zend_hash_get_current_key_ex(Z_OBJPROP(disp->object), &name,
441-
&pid, &pos))) {
442-
char namebuf[32];
443-
if (keytype == HASH_KEY_IS_LONG) {
444-
snprintf(namebuf, sizeof(namebuf), ZEND_ULONG_FMT, pid);
445-
name = zend_string_init(namebuf, strlen(namebuf), 0);
446-
} else {
447-
zend_string_addref(name);
448-
}
449-
450-
zend_hash_move_forward_ex(Z_OBJPROP(disp->object), &pos);
436+
ZEND_HASH_FOREACH_STR_KEY(Z_OBJPROP(disp->object), name) {
437+
ZEND_ASSERT(name);
451438

452-
/* Find the existing id */
453-
if ((tmp = zend_hash_find(disp->name_to_dispid, name)) != NULL) {
454-
zend_string_release_ex(name, 0);
439+
/* Check ID exists */
440+
if (!zend_hash_exists(disp->name_to_dispid, name)) {
455441
continue;
456442
}
457443

458444
/* add the mappings */
459-
ZVAL_STR_COPY(&tmp2, name);
460-
zend_hash_next_index_insert(disp->dispid_to_name, &tmp2);
461-
pid = zend_hash_next_free_element(disp->dispid_to_name) - 1;
462-
463-
ZVAL_LONG(&tmp2, pid);
464-
zend_hash_update(disp->name_to_dispid, name, &tmp2);
445+
ZVAL_STR_COPY(&tmp, name);
446+
pid = zend_hash_next_free_element(disp->dispid_to_name);
447+
zend_hash_index_update(disp->dispid_to_name, pid, &tmp);
465448

466-
zend_string_release_ex(name, 0);
467-
}
449+
ZVAL_LONG(&tmp, pid);
450+
zend_hash_update(disp->name_to_dispid, name, &tmp);
451+
} ZEND_HASH_FOREACH_END();
468452
}
469453

470454
/* functions */
471455
if (Z_OBJCE(disp->object)) {
472-
zend_hash_internal_pointer_reset_ex(&Z_OBJCE(disp->object)->function_table, &pos);
473-
while (HASH_KEY_NON_EXISTENT != (keytype =
474-
zend_hash_get_current_key_ex(&Z_OBJCE(disp->object)->function_table,
475-
&name, &pid, &pos))) {
476-
477-
char namebuf[32];
478-
if (keytype == HASH_KEY_IS_LONG) {
479-
snprintf(namebuf, sizeof(namebuf), ZEND_ULONG_FMT, pid);
480-
name = zend_string_init(namebuf, strlen(namebuf), 0);
481-
} else {
482-
zend_string_addref(name);
483-
}
484-
485-
zend_hash_move_forward_ex(&Z_OBJCE(disp->object)->function_table, &pos);
456+
ZEND_HASH_FOREACH_STR_KEY(&Z_OBJCE(disp->object)->function_table, name) {
457+
ZEND_ASSERT(name);
486458

487-
/* Find the existing id */
488-
if ((tmp = zend_hash_find(disp->name_to_dispid, name)) != NULL) {
489-
zend_string_release_ex(name, 0);
459+
/* Check ID exists */
460+
if (!zend_hash_exists(disp->name_to_dispid, name)) {
490461
continue;
491462
}
492463

493464
/* add the mappings */
494-
ZVAL_STR_COPY(&tmp2, name);
495-
zend_hash_next_index_insert(disp->dispid_to_name, &tmp2);
496-
pid = zend_hash_next_free_element(disp->dispid_to_name) - 1;
497-
498-
ZVAL_LONG(&tmp2, pid);
499-
zend_hash_update(disp->name_to_dispid, name, &tmp2);
465+
ZVAL_STR_COPY(&tmp, name);
466+
pid = zend_hash_next_free_element(disp->dispid_to_name);
467+
zend_hash_index_update(disp->dispid_to_name, pid, &tmp);
500468

501-
zend_string_release_ex(name, 0);
502-
}
469+
ZVAL_LONG(&tmp, pid);
470+
zend_hash_update(disp->name_to_dispid, name, &tmp);
471+
} ZEND_HASH_FOREACH_END();
503472
}
504473
}
505474

@@ -540,15 +509,9 @@ static void disp_destructor(php_dispatchex *disp)
540509
CoTaskMemFree(disp);
541510
}
542511

543-
PHP_COM_DOTNET_API IDispatch *php_com_wrapper_export_as_sink(zval *val, GUID *sinkid,
544-
HashTable *id_to_name)
512+
PHP_COM_DOTNET_API IDispatch *php_com_wrapper_export_as_sink(zval *val, GUID *sinkid, HashTable *id_to_name)
545513
{
546514
php_dispatchex *disp = disp_constructor(val);
547-
HashPosition pos;
548-
zend_string *name = NULL;
549-
zval tmp, *ntmp;
550-
int keytype;
551-
zend_ulong pid;
552515

553516
disp->dispid_to_name = id_to_name;
554517

@@ -558,20 +521,16 @@ PHP_COM_DOTNET_API IDispatch *php_com_wrapper_export_as_sink(zval *val, GUID *si
558521
ALLOC_HASHTABLE(disp->name_to_dispid);
559522
zend_hash_init(disp->name_to_dispid, 0, NULL, ZVAL_PTR_DTOR, 0);
560523

561-
zend_hash_internal_pointer_reset_ex(id_to_name, &pos);
562-
while (HASH_KEY_NON_EXISTENT != (keytype =
563-
zend_hash_get_current_key_ex(id_to_name, &name, &pid, &pos))) {
564-
565-
if (keytype == HASH_KEY_IS_LONG) {
566-
567-
ntmp = zend_hash_get_current_data_ex(id_to_name, &pos);
568-
569-
ZVAL_LONG(&tmp, pid);
570-
zend_hash_update(disp->name_to_dispid, Z_STR_P(ntmp), &tmp);
571-
}
572-
573-
zend_hash_move_forward_ex(id_to_name, &pos);
574-
}
524+
ZEND_ASSERT(zend_array_is_list(id_to_name));
525+
zend_ulong pid;
526+
zval *value;
527+
ZEND_HASH_FOREACH_NUM_KEY_VAL(id_to_name, pid, value) {
528+
ZEND_ASSERT(Z_TYPE_P(value) == IS_STRING);
529+
530+
zval tmp;
531+
ZVAL_LONG(&tmp, pid);
532+
zend_hash_update(disp->name_to_dispid, Z_STR_P(value), &tmp);
533+
} ZEND_HASH_FOREACH_END();
575534

576535
return (IDispatch*)disp;
577536
}

0 commit comments

Comments
 (0)