1 /*
2 * Copyright 2018-present MongoDB, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <php.h>
18 #include <Zend/zend_interfaces.h>
19 #include <ext/standard/php_var.h>
20 #include <zend_smart_str.h>
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "phongo_compat.h"
27 #include "php_phongo.h"
28 #include "php_bson.h"
29
30 zend_class_entry* php_phongo_int64_ce;
31
32 /* Initialize the object and return whether it was successful. */
php_phongo_int64_init(php_phongo_int64_t * intern,int64_t integer)33 static bool php_phongo_int64_init(php_phongo_int64_t* intern, int64_t integer) /* {{{ */
34 {
35 intern->integer = integer;
36 intern->initialized = true;
37
38 return true;
39 } /* }}} */
40
41 /* Initialize the object from a numeric string and return whether it was
42 * successful. An exception will be thrown on error. */
php_phongo_int64_init_from_string(php_phongo_int64_t * intern,const char * s_integer,size_t s_integer_len)43 static bool php_phongo_int64_init_from_string(php_phongo_int64_t* intern, const char* s_integer, size_t s_integer_len) /* {{{ */
44 {
45 int64_t integer;
46
47 if (!php_phongo_parse_int64(&integer, s_integer, s_integer_len)) {
48 phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error parsing \"%s\" as 64-bit integer for %s initialization", s_integer, ZSTR_VAL(php_phongo_int64_ce->name));
49 return false;
50 }
51
52 return php_phongo_int64_init(intern, integer);
53 } /* }}} */
54
55 /* Initialize the object from a HashTable and return whether it was successful.
56 * An exception will be thrown on error. */
php_phongo_int64_init_from_hash(php_phongo_int64_t * intern,HashTable * props)57 static bool php_phongo_int64_init_from_hash(php_phongo_int64_t* intern, HashTable* props) /* {{{ */
58 {
59 zval* value;
60
61 if ((value = zend_hash_str_find(props, "integer", sizeof("integer") - 1)) && Z_TYPE_P(value) == IS_STRING) {
62 return php_phongo_int64_init_from_string(intern, Z_STRVAL_P(value), Z_STRLEN_P(value));
63 }
64
65 phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"integer\" string field", ZSTR_VAL(php_phongo_int64_ce->name));
66 return false;
67 } /* }}} */
68
69 /* {{{ proto string MongoDB\BSON\Int64::__toString()
70 Return the Int64's value as a string. */
PHP_METHOD(Int64,__toString)71 static PHP_METHOD(Int64, __toString)
72 {
73 zend_error_handling error_handling;
74 php_phongo_int64_t* intern;
75
76 zend_replace_error_handling(EH_THROW, phongo_exception_from_phongo_domain(PHONGO_ERROR_INVALID_ARGUMENT), &error_handling);
77 if (zend_parse_parameters_none() == FAILURE) {
78 zend_restore_error_handling(&error_handling);
79 return;
80 }
81 zend_restore_error_handling(&error_handling);
82
83 intern = Z_INT64_OBJ_P(getThis());
84
85 ZVAL_INT64_STRING(return_value, intern->integer);
86 } /* }}} */
87
88 /* {{{ proto array MongoDB\BSON\Int64::jsonSerialize()
89 */
PHP_METHOD(Int64,jsonSerialize)90 static PHP_METHOD(Int64, jsonSerialize)
91 {
92 zend_error_handling error_handling;
93 php_phongo_int64_t* intern;
94
95 zend_replace_error_handling(EH_THROW, phongo_exception_from_phongo_domain(PHONGO_ERROR_INVALID_ARGUMENT), &error_handling);
96 if (zend_parse_parameters_none() == FAILURE) {
97 zend_restore_error_handling(&error_handling);
98 return;
99 }
100 zend_restore_error_handling(&error_handling);
101
102 intern = Z_INT64_OBJ_P(getThis());
103
104 array_init_size(return_value, 1);
105
106 ADD_ASSOC_INT64_AS_STRING(return_value, "$numberLong", intern->integer);
107 } /* }}} */
108
109 /* {{{ proto string MongoDB\BSON\Int64::serialize()
110 */
PHP_METHOD(Int64,serialize)111 static PHP_METHOD(Int64, serialize)
112 {
113 zend_error_handling error_handling;
114 php_phongo_int64_t* intern;
115 zval retval;
116 php_serialize_data_t var_hash;
117 smart_str buf = { 0 };
118
119 zend_replace_error_handling(EH_THROW, phongo_exception_from_phongo_domain(PHONGO_ERROR_INVALID_ARGUMENT), &error_handling);
120 if (zend_parse_parameters_none() == FAILURE) {
121 zend_restore_error_handling(&error_handling);
122 return;
123 }
124 zend_restore_error_handling(&error_handling);
125
126 intern = Z_INT64_OBJ_P(getThis());
127
128 array_init_size(&retval, 1);
129 ADD_ASSOC_INT64_AS_STRING(&retval, "integer", intern->integer);
130
131 PHP_VAR_SERIALIZE_INIT(var_hash);
132 php_var_serialize(&buf, &retval, &var_hash);
133 smart_str_0(&buf);
134 PHP_VAR_SERIALIZE_DESTROY(var_hash);
135
136 PHONGO_RETVAL_SMART_STR(buf);
137
138 smart_str_free(&buf);
139 zval_ptr_dtor(&retval);
140 } /* }}} */
141
142 /* {{{ proto void MongoDB\BSON\Int64::unserialize(string $serialized)
143 */
PHP_METHOD(Int64,unserialize)144 static PHP_METHOD(Int64, unserialize)
145 {
146 zend_error_handling error_handling;
147 php_phongo_int64_t* intern;
148 char* serialized;
149 size_t serialized_len;
150 zval props;
151 php_unserialize_data_t var_hash;
152
153 intern = Z_INT64_OBJ_P(getThis());
154
155 zend_replace_error_handling(EH_THROW, phongo_exception_from_phongo_domain(PHONGO_ERROR_INVALID_ARGUMENT), &error_handling);
156 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &serialized, &serialized_len) == FAILURE) {
157 zend_restore_error_handling(&error_handling);
158 return;
159 }
160 zend_restore_error_handling(&error_handling);
161
162 PHP_VAR_UNSERIALIZE_INIT(var_hash);
163 if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) {
164 zval_ptr_dtor(&props);
165 phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_int64_ce->name));
166
167 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
168 return;
169 }
170 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
171
172 php_phongo_int64_init_from_hash(intern, HASH_OF(&props));
173 zval_ptr_dtor(&props);
174 } /* }}} */
175
176 /* {{{ MongoDB\BSON\Int64 function entries */
177 ZEND_BEGIN_ARG_INFO_EX(ai_Int64_unserialize, 0, 0, 1)
178 ZEND_ARG_INFO(0, serialized)
179 ZEND_END_ARG_INFO()
180
181 ZEND_BEGIN_ARG_INFO_EX(ai_Int64_void, 0, 0, 0)
182 ZEND_END_ARG_INFO()
183
184 static zend_function_entry php_phongo_int64_me[] = {
185 /* clang-format off */
186 /* __set_state intentionally missing */
187 PHP_ME(Int64, __toString, ai_Int64_void, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL)
188 PHP_ME(Int64, jsonSerialize, ai_Int64_void, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL)
189 PHP_ME(Int64, serialize, ai_Int64_void, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL)
190 PHP_ME(Int64, unserialize, ai_Int64_unserialize, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL)
191 ZEND_NAMED_ME(__construct, PHP_FN(MongoDB_disabled___construct), ai_Int64_void, ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)
192 PHP_FE_END
193 /* clang-format on */
194 };
195 /* }}} */
196
197 /* {{{ MongoDB\BSON\Int64 object handlers */
198 static zend_object_handlers php_phongo_handler_int64;
199
php_phongo_int64_free_object(zend_object * object)200 static void php_phongo_int64_free_object(zend_object* object) /* {{{ */
201 {
202 php_phongo_int64_t* intern = Z_OBJ_INT64(object);
203
204 zend_object_std_dtor(&intern->std);
205
206 if (intern->properties) {
207 zend_hash_destroy(intern->properties);
208 FREE_HASHTABLE(intern->properties);
209 }
210 } /* }}} */
211
php_phongo_int64_create_object(zend_class_entry * class_type)212 zend_object* php_phongo_int64_create_object(zend_class_entry* class_type) /* {{{ */
213 {
214 php_phongo_int64_t* intern = NULL;
215
216 intern = PHONGO_ALLOC_OBJECT_T(php_phongo_int64_t, class_type);
217 zend_object_std_init(&intern->std, class_type);
218 object_properties_init(&intern->std, class_type);
219
220 intern->std.handlers = &php_phongo_handler_int64;
221
222 return &intern->std;
223 } /* }}} */
224
php_phongo_int64_clone_object(phongo_compat_object_handler_type * object)225 static zend_object* php_phongo_int64_clone_object(phongo_compat_object_handler_type* object) /* {{{ */
226 {
227 php_phongo_int64_t* intern;
228 php_phongo_int64_t* new_intern;
229 zend_object* new_object;
230
231 intern = Z_OBJ_INT64(PHONGO_COMPAT_GET_OBJ(object));
232 new_object = php_phongo_int64_create_object(PHONGO_COMPAT_GET_OBJ(object)->ce);
233
234 new_intern = Z_OBJ_INT64(new_object);
235 zend_objects_clone_members(&new_intern->std, &intern->std);
236
237 php_phongo_int64_init(new_intern, intern->integer);
238
239 return new_object;
240 } /* }}} */
241
php_phongo_int64_compare_objects(zval * o1,zval * o2)242 static int php_phongo_int64_compare_objects(zval* o1, zval* o2) /* {{{ */
243 {
244 php_phongo_int64_t *intern1, *intern2;
245
246 ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2);
247
248 intern1 = Z_INT64_OBJ_P(o1);
249 intern2 = Z_INT64_OBJ_P(o2);
250
251 if (intern1->integer != intern2->integer) {
252 return intern1->integer < intern2->integer ? -1 : 1;
253 }
254
255 return 0;
256 } /* }}} */
257
php_phongo_int64_get_properties_hash(phongo_compat_object_handler_type * object,bool is_debug)258 HashTable* php_phongo_int64_get_properties_hash(phongo_compat_object_handler_type* object, bool is_debug) /* {{{ */
259 {
260 php_phongo_int64_t* intern;
261 HashTable* props;
262
263 intern = Z_OBJ_INT64(PHONGO_COMPAT_GET_OBJ(object));
264
265 PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_debug, intern, props, 2);
266
267 if (!intern->initialized) {
268 return props;
269 }
270
271 {
272 zval value;
273
274 ZVAL_INT64_STRING(&value, intern->integer);
275 zend_hash_str_update(props, "integer", sizeof("integer") - 1, &value);
276 }
277
278 return props;
279 } /* }}} */
280
php_phongo_int64_get_debug_info(phongo_compat_object_handler_type * object,int * is_temp)281 static HashTable* php_phongo_int64_get_debug_info(phongo_compat_object_handler_type* object, int* is_temp) /* {{{ */
282 {
283 *is_temp = 1;
284 return php_phongo_int64_get_properties_hash(object, true);
285 } /* }}} */
286
php_phongo_int64_get_properties(phongo_compat_object_handler_type * object)287 static HashTable* php_phongo_int64_get_properties(phongo_compat_object_handler_type* object) /* {{{ */
288 {
289 return php_phongo_int64_get_properties_hash(object, false);
290 } /* }}} */
291 /* }}} */
292
php_phongo_int64_init_ce(INIT_FUNC_ARGS)293 void php_phongo_int64_init_ce(INIT_FUNC_ARGS) /* {{{ */
294 {
295 zend_class_entry ce;
296
297 INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Int64", php_phongo_int64_me);
298 php_phongo_int64_ce = zend_register_internal_class(&ce);
299 php_phongo_int64_ce->create_object = php_phongo_int64_create_object;
300 PHONGO_CE_FINAL(php_phongo_int64_ce);
301
302 zend_class_implements(php_phongo_int64_ce, 1, php_phongo_json_serializable_ce);
303 zend_class_implements(php_phongo_int64_ce, 1, php_phongo_type_ce);
304 zend_class_implements(php_phongo_int64_ce, 1, zend_ce_serializable);
305
306 memcpy(&php_phongo_handler_int64, phongo_get_std_object_handlers(), sizeof(zend_object_handlers));
307 PHONGO_COMPAT_SET_COMPARE_OBJECTS_HANDLER(int64);
308 php_phongo_handler_int64.clone_obj = php_phongo_int64_clone_object;
309 php_phongo_handler_int64.get_debug_info = php_phongo_int64_get_debug_info;
310 php_phongo_handler_int64.get_properties = php_phongo_int64_get_properties;
311 php_phongo_handler_int64.free_obj = php_phongo_int64_free_object;
312 php_phongo_handler_int64.offset = XtOffsetOf(php_phongo_int64_t, std);
313 } /* }}} */
314
315 /*
316 * Local variables:
317 * tab-width: 4
318 * c-basic-offset: 4
319 * End:
320 * vim600: noet sw=4 ts=4 fdm=marker
321 * vim<600: noet sw=4 ts=4
322 */
323