1 #include "common.h"
2
ds_allocate_zval_buffer(zend_long length)3 zval *ds_allocate_zval_buffer(zend_long length)
4 {
5 return ecalloc(length, sizeof(zval));
6 }
7
ds_next_power_of_2(uint32_t n,uint32_t min)8 uint32_t ds_next_power_of_2(uint32_t n, uint32_t min)
9 {
10 if (n < min) return min;
11
12 n--;
13 n |= n >> 1;
14 n |= n >> 2;
15 n |= n >> 4;
16 n |= n >> 8;
17 n |= n >> 16;
18 n++;
19
20 return n;
21 }
22
ds_reallocate_zval_buffer(zval * buffer,zend_long length,zend_long current,zend_long used)23 zval *ds_reallocate_zval_buffer(
24 zval *buffer,
25 zend_long length,
26 zend_long current,
27 zend_long used
28 ) {
29 if (length == current) {
30 return buffer;
31 }
32
33 // Destruct zvals if we're truncating the buffer.
34 if (length < used) {
35 zend_long i;
36
37 for (i = length; i < used; i++) {
38 DTOR_AND_UNDEF(&buffer[i]);
39 }
40 }
41
42 buffer = erealloc(buffer, length * sizeof(zval));
43
44 // Clear out any new memory that was allocated.
45 if (length > current) {
46 memset(buffer + current, 0, (length - current) * sizeof(zval));
47 }
48
49 return buffer;
50 }
51
ds_zval_user_compare_func(const void * a,const void * b)52 static int ds_zval_user_compare_func(const void *a, const void *b)
53 {
54 zval params[2];
55 zval retval;
56
57 zval *x = (zval*) a;
58 zval *y = (zval*) b;
59
60 ZVAL_COPY_VALUE(¶ms[0], x);
61 ZVAL_COPY_VALUE(¶ms[1], y);
62
63 DSG(user_compare_fci).param_count = 2;
64 DSG(user_compare_fci).params = params;
65 DSG(user_compare_fci).retval = &retval;
66
67 if (zend_call_function(
68 &DSG(user_compare_fci),
69 &DSG(user_compare_fci_cache)) == SUCCESS) {
70
71 return (int) zval_get_long(&retval);
72 }
73
74 return 0;
75 }
76
ds_zval_compare_func(const void * a,const void * b)77 static int ds_zval_compare_func(const void *a, const void *b)
78 {
79 zval retval;
80
81 zval *x = (zval*) a;
82 zval *y = (zval*) b;
83
84 if (compare_function(&retval, x, y) == SUCCESS) {
85 return (int) zval_get_long(&retval);
86 }
87
88 return 0;
89 }
90
ds_sort_zval_buffer(zval * buffer,zend_long size)91 void ds_sort_zval_buffer(zval *buffer, zend_long size)
92 {
93 qsort(buffer, size, sizeof(zval), ds_zval_compare_func);
94 }
95
ds_user_sort_zval_buffer(zval * buffer,zend_long size)96 void ds_user_sort_zval_buffer(zval *buffer, zend_long size)
97 {
98 qsort(buffer, size, sizeof(zval), ds_zval_user_compare_func);
99 }
100
ds_zval_isset(zval * value,int check_empty)101 int ds_zval_isset(zval *value, int check_empty)
102 {
103 if (value == NULL) {
104 return 0;
105 }
106
107 if ( ! check_empty) {
108 return Z_TYPE_P(value) != IS_NULL;
109 }
110
111 return zend_is_true(value);
112 }
113
ds_normalize_slice_args(zend_long * offset,zend_long * length,zend_long size)114 void ds_normalize_slice_args(
115 zend_long *offset,
116 zend_long *length,
117 zend_long size
118 ) {
119 zend_long idx = *offset;
120 zend_long len = *length;
121
122 // If the offset is beyond the end or the length is zero, it's an empty slice.
123 if (size == 0 || idx >= size) {
124 *offset = 0;
125 *length = 0;
126
127 } else {
128
129 // If index is negative, start that far from the end.
130 if (idx < 0) {
131 idx = MAX(0, size + idx);
132 }
133
134 // If length is given and negative, stop that far from the end.
135 if (len < 0) {
136 len = MAX(0, (size + len) - idx);
137 }
138
139 // If the length extends beyond the end, only go up to the end.
140 if ((idx + len) > size) {
141 len = MAX(0, size - idx);
142 }
143
144 *offset = idx;
145 *length = len;
146 }
147 }
148
smart_str_appendz(smart_str * buffer,zval * value)149 void smart_str_appendz(smart_str *buffer, zval *value)
150 {
151 switch (Z_TYPE_P(value)) {
152 case IS_STRING:
153 smart_str_append(buffer, Z_STR_P(value));
154 return;
155 case IS_LONG:
156 smart_str_append_long(buffer, Z_LVAL_P(value));
157 return;
158 }
159
160 zend_string *str = zval_get_string(value);
161 smart_str_append(buffer, str);
162 zend_string_free(str);
163 }
164
ds_join_zval_buffer(zval * buffer,zend_long size,char * glue,size_t len)165 zend_string *ds_join_zval_buffer(
166 zval *buffer,
167 zend_long size,
168 char *glue,
169 size_t len
170 ) {
171 smart_str str = {0};
172
173 if (size <= 0) {
174 return ZSTR_EMPTY_ALLOC();
175 }
176
177 if (size == 1) {
178 return zval_get_string(buffer);
179 }
180
181 // Glue is optional, will use empty string by default if NULL
182 if (glue && len) {
183 zval *pos = buffer;
184 zval *end = buffer + size - 1; // Exclude last value
185
186 // Append each part and the glue right up to the last value.
187 do {
188 smart_str_appendz(&str, pos);
189 smart_str_appendl(&str, glue, len);
190 } while (++pos != end);
191
192 // Append last value
193 smart_str_appendz(&str, pos);
194
195 } else {
196 zval *pos = buffer;
197 zval *end = buffer + size;
198
199 // Append each part including the last, without glue.
200 do {
201 smart_str_appendz(&str, pos);
202 } while (++pos != end);
203 }
204
205 smart_str_0(&str);
206 return str.s;
207 }
208
ds_is_traversable(zval * value)209 bool ds_is_traversable(zval *value)
210 {
211 return Z_TYPE_P(value) == IS_OBJECT &&
212 instanceof_function(Z_OBJCE_P(value), zend_ce_traversable);
213 }
214
ds_is_array(zval * value)215 bool ds_is_array(zval *value)
216 {
217 return Z_TYPE_P(value) == IS_ARRAY;
218 }
219
ds_php_array_uses_keys(HashTable * ht)220 bool ds_php_array_uses_keys(HashTable *ht)
221 {
222 zend_string *key;
223 zend_long index;
224 zend_long expected = 0;
225
226 ZEND_HASH_FOREACH_KEY(ht, index, key) {
227 if (key || index != expected++) {
228 return true;
229 }
230 }
231
232 ZEND_HASH_FOREACH_END();
233 return false;
234 }
235
ds_reverse_zval_range(zval * x,zval * y)236 void ds_reverse_zval_range(zval *x, zval *y)
237 {
238 for (; x < --y; ++x) SWAP_ZVAL(*x, *y);
239 }
240
ds_throw_exception(zend_class_entry * ce,const char * format,...)241 void ds_throw_exception(zend_class_entry *ce, const char *format, ...)
242 {
243 va_list ap;
244 zend_string *str;
245
246 va_start(ap, format);
247 str = vstrpprintf(0, format, ap);
248 va_end(ap);
249
250 zend_throw_exception(ce, str->val, 0);
251 zend_string_free(str);
252 }
253