OLD | NEW |
| (Empty) |
1 // Protocol Buffers - Google's data interchange format | |
2 // Copyright 2008 Google Inc. All rights reserved. | |
3 // https://developers.google.com/protocol-buffers/ | |
4 // | |
5 // Redistribution and use in source and binary forms, with or without | |
6 // modification, are permitted provided that the following conditions are | |
7 // met: | |
8 // | |
9 // * Redistributions of source code must retain the above copyright | |
10 // notice, this list of conditions and the following disclaimer. | |
11 // * Redistributions in binary form must reproduce the above | |
12 // copyright notice, this list of conditions and the following disclaimer | |
13 // in the documentation and/or other materials provided with the | |
14 // distribution. | |
15 // * Neither the name of Google Inc. nor the names of its | |
16 // contributors may be used to endorse or promote products derived from | |
17 // this software without specific prior written permission. | |
18 // | |
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
30 | |
31 #include <Zend/zend_operators.h> | |
32 | |
33 #include "protobuf.h" | |
34 #include "utf8.h" | |
35 | |
36 static zend_class_entry* util_type; | |
37 static const char int64_min_digits[] = "9223372036854775808"; | |
38 | |
39 ZEND_BEGIN_ARG_INFO_EX(arg_check_optional, 0, 0, 1) | |
40 ZEND_ARG_INFO(1, val) | |
41 ZEND_END_ARG_INFO() | |
42 | |
43 ZEND_BEGIN_ARG_INFO_EX(arg_check_message, 0, 0, 2) | |
44 ZEND_ARG_INFO(1, val) | |
45 ZEND_ARG_INFO(0, klass) | |
46 ZEND_END_ARG_INFO() | |
47 | |
48 ZEND_BEGIN_ARG_INFO_EX(arg_check_repeated, 0, 0, 2) | |
49 ZEND_ARG_INFO(1, val) | |
50 ZEND_ARG_INFO(0, type) | |
51 ZEND_ARG_INFO(0, klass) | |
52 ZEND_END_ARG_INFO() | |
53 | |
54 static zend_function_entry util_methods[] = { | |
55 PHP_ME(Util, checkInt32, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) | |
56 PHP_ME(Util, checkUint32, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) | |
57 PHP_ME(Util, checkInt64, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) | |
58 PHP_ME(Util, checkUint64, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) | |
59 PHP_ME(Util, checkEnum, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) | |
60 PHP_ME(Util, checkFloat, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) | |
61 PHP_ME(Util, checkDouble, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) | |
62 PHP_ME(Util, checkBool, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) | |
63 PHP_ME(Util, checkString, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) | |
64 PHP_ME(Util, checkBytes, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) | |
65 PHP_ME(Util, checkMessage, arg_check_message, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) | |
66 PHP_ME(Util, checkRepeatedField, arg_check_repeated, | |
67 ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) | |
68 ZEND_FE_END | |
69 }; | |
70 | |
71 void util_init(TSRMLS_D) { | |
72 zend_class_entry class_type; | |
73 INIT_CLASS_ENTRY(class_type, "Google\\Protobuf\\Internal\\GPBUtil", | |
74 util_methods); | |
75 util_type = zend_register_internal_class(&class_type TSRMLS_CC); | |
76 } | |
77 | |
78 // ----------------------------------------------------------------------------- | |
79 // Type checking/conversion. | |
80 // ----------------------------------------------------------------------------- | |
81 | |
82 // This is modified from is_numeric_string in zend_operators.h. The behavior of | |
83 // this function is the same as is_numeric_string, except that this takes | |
84 // int64_t as input instead of long. | |
85 static zend_uchar convert_numeric_string( | |
86 const char *str, int length, int64_t *lval, double *dval) { | |
87 const char *ptr; | |
88 int base = 10, digits = 0, dp_or_e = 0; | |
89 double local_dval = 0.0; | |
90 zend_uchar type; | |
91 | |
92 if (length == 0) { | |
93 return IS_NULL; | |
94 } | |
95 | |
96 while (*str == ' ' || *str == '\t' || *str == '\n' || | |
97 *str == '\r' || *str == '\v' || *str == '\f') { | |
98 str++; | |
99 length--; | |
100 } | |
101 ptr = str; | |
102 | |
103 if (*ptr == '-' || *ptr == '+') { | |
104 ptr++; | |
105 } | |
106 | |
107 if (ZEND_IS_DIGIT(*ptr)) { | |
108 // Handle hex numbers | |
109 // str is used instead of ptr to disallow signs and keep old behavior. | |
110 if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) { | |
111 base = 16; | |
112 ptr += 2; | |
113 } | |
114 | |
115 // Skip any leading 0s. | |
116 while (*ptr == '0') { | |
117 ptr++; | |
118 } | |
119 | |
120 // Count the number of digits. If a decimal point/exponent is found, | |
121 // it's a double. Otherwise, if there's a dval or no need to check for | |
122 // a full match, stop when there are too many digits for a int64 */ | |
123 for (type = IS_LONG; | |
124 !(digits >= MAX_LENGTH_OF_INT64 && dval); | |
125 digits++, ptr++) { | |
126 check_digits: | |
127 if (ZEND_IS_DIGIT(*ptr) || (base == 16 && ZEND_IS_XDIGIT(*ptr))) { | |
128 continue; | |
129 } else if (base == 10) { | |
130 if (*ptr == '.' && dp_or_e < 1) { | |
131 goto process_double; | |
132 } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) { | |
133 const char *e = ptr + 1; | |
134 | |
135 if (*e == '-' || *e == '+') { | |
136 ptr = e++; | |
137 } | |
138 if (ZEND_IS_DIGIT(*e)) { | |
139 goto process_double; | |
140 } | |
141 } | |
142 } | |
143 break; | |
144 } | |
145 | |
146 if (base == 10) { | |
147 if (digits >= MAX_LENGTH_OF_INT64) { | |
148 dp_or_e = -1; | |
149 goto process_double; | |
150 } | |
151 } else if (!(digits < SIZEOF_INT64 * 2 || | |
152 (digits == SIZEOF_INT64 * 2 && ptr[-digits] <= '7'))) { | |
153 if (dval) { | |
154 local_dval = zend_hex_strtod(str, &ptr); | |
155 } | |
156 type = IS_DOUBLE; | |
157 } | |
158 } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) { | |
159 process_double: | |
160 type = IS_DOUBLE; | |
161 | |
162 // If there's a dval, do the conversion; else continue checking | |
163 // the digits if we need to check for a full match. | |
164 if (dval) { | |
165 local_dval = zend_strtod(str, &ptr); | |
166 } else if (dp_or_e != -1) { | |
167 dp_or_e = (*ptr++ == '.') ? 1 : 2; | |
168 goto check_digits; | |
169 } | |
170 } else { | |
171 return IS_NULL; | |
172 } | |
173 if (ptr != str + length) { | |
174 zend_error(E_NOTICE, "A non well formed numeric value encountered"); | |
175 return 0; | |
176 } | |
177 | |
178 if (type == IS_LONG) { | |
179 if (digits == MAX_LENGTH_OF_INT64 - 1) { | |
180 int cmp = strcmp(&ptr[-digits], int64_min_digits); | |
181 | |
182 if (!(cmp < 0 || (cmp == 0 && *str == '-'))) { | |
183 if (dval) { | |
184 *dval = zend_strtod(str, NULL); | |
185 } | |
186 | |
187 return IS_DOUBLE; | |
188 } | |
189 } | |
190 if (lval) { | |
191 *lval = strtoll(str, NULL, base); | |
192 } | |
193 return IS_LONG; | |
194 } else { | |
195 if (dval) { | |
196 *dval = local_dval; | |
197 } | |
198 return IS_DOUBLE; | |
199 } | |
200 } | |
201 | |
202 #define CONVERT_TO_INTEGER(type) \ | |
203 static bool convert_int64_to_##type(int64_t val, type##_t* type##_value) { \ | |
204 *type##_value = (type##_t)val; \ | |
205 return true; \ | |
206 } \ | |
207 \ | |
208 static bool convert_double_to_##type(double val, type##_t* type##_value) { \ | |
209 *type##_value = (type##_t)zend_dval_to_lval(val); \ | |
210 return true; \ | |
211 } \ | |
212 \ | |
213 static bool convert_string_to_##type(const char* val, int len, \ | |
214 type##_t* type##_value) { \ | |
215 int64_t lval; \ | |
216 double dval; \ | |
217 \ | |
218 switch (convert_numeric_string(val, len, &lval, &dval)) { \ | |
219 case IS_DOUBLE: { \ | |
220 return convert_double_to_##type(dval, type##_value); \ | |
221 } \ | |
222 case IS_LONG: { \ | |
223 return convert_int64_to_##type(lval, type##_value); \ | |
224 } \ | |
225 default: \ | |
226 zend_error(E_USER_ERROR, \ | |
227 "Given string value cannot be converted to integer."); \ | |
228 return false; \ | |
229 } \ | |
230 } \ | |
231 \ | |
232 bool protobuf_convert_to_##type(zval* from, type##_t* to) { \ | |
233 switch (Z_TYPE_P(from)) { \ | |
234 case IS_LONG: { \ | |
235 return convert_int64_to_##type(Z_LVAL_P(from), to); \ | |
236 } \ | |
237 case IS_DOUBLE: { \ | |
238 return convert_double_to_##type(Z_DVAL_P(from), to); \ | |
239 } \ | |
240 case IS_STRING: { \ | |
241 return convert_string_to_##type(Z_STRVAL_P(from), Z_STRLEN_P(from), \ | |
242 to); \ | |
243 } \ | |
244 default: { \ | |
245 zend_error(E_USER_ERROR, \ | |
246 "Given value cannot be converted to integer."); \ | |
247 return false; \ | |
248 } \ | |
249 } \ | |
250 return false; \ | |
251 } | |
252 | |
253 CONVERT_TO_INTEGER(int32); | |
254 CONVERT_TO_INTEGER(uint32); | |
255 CONVERT_TO_INTEGER(int64); | |
256 CONVERT_TO_INTEGER(uint64); | |
257 | |
258 #undef CONVERT_TO_INTEGER | |
259 | |
260 #define CONVERT_TO_FLOAT(type) \ | |
261 static bool convert_int64_to_##type(int64_t val, type* type##_value) { \ | |
262 *type##_value = (type)val; \ | |
263 return true; \ | |
264 } \ | |
265 \ | |
266 static bool convert_double_to_##type(double val, type* type##_value) { \ | |
267 *type##_value = (type)val; \ | |
268 return true; \ | |
269 } \ | |
270 \ | |
271 static bool convert_string_to_##type(const char* val, int len, \ | |
272 type* type##_value) { \ | |
273 int64_t lval; \ | |
274 double dval; \ | |
275 \ | |
276 switch (convert_numeric_string(val, len, &lval, &dval)) { \ | |
277 case IS_DOUBLE: { \ | |
278 *type##_value = (type)dval; \ | |
279 return true; \ | |
280 } \ | |
281 case IS_LONG: { \ | |
282 *type##_value = (type)lval; \ | |
283 return true; \ | |
284 } \ | |
285 default: \ | |
286 zend_error(E_USER_ERROR, \ | |
287 "Given string value cannot be converted to integer."); \ | |
288 return false; \ | |
289 } \ | |
290 } \ | |
291 \ | |
292 bool protobuf_convert_to_##type(zval* from, type* to) { \ | |
293 switch (Z_TYPE_P(from)) { \ | |
294 case IS_LONG: { \ | |
295 return convert_int64_to_##type(Z_LVAL_P(from), to); \ | |
296 } \ | |
297 case IS_DOUBLE: { \ | |
298 return convert_double_to_##type(Z_DVAL_P(from), to); \ | |
299 } \ | |
300 case IS_STRING: { \ | |
301 return convert_string_to_##type(Z_STRVAL_P(from), Z_STRLEN_P(from), \ | |
302 to); \ | |
303 } \ | |
304 default: { \ | |
305 zend_error(E_USER_ERROR, \ | |
306 "Given value cannot be converted to integer."); \ | |
307 return false; \ | |
308 } \ | |
309 } \ | |
310 return false; \ | |
311 } | |
312 | |
313 CONVERT_TO_FLOAT(float); | |
314 CONVERT_TO_FLOAT(double); | |
315 | |
316 #undef CONVERT_TO_FLOAT | |
317 | |
318 bool protobuf_convert_to_bool(zval* from, int8_t* to) { | |
319 switch (Z_TYPE_P(from)) { | |
320 case IS_BOOL: | |
321 *to = (int8_t)Z_BVAL_P(from); | |
322 break; | |
323 case IS_LONG: | |
324 *to = (int8_t)(Z_LVAL_P(from) != 0); | |
325 break; | |
326 case IS_DOUBLE: | |
327 *to = (int8_t)(Z_LVAL_P(from) != 0); | |
328 break; | |
329 case IS_STRING: { | |
330 char* strval = Z_STRVAL_P(from); | |
331 | |
332 if (Z_STRLEN_P(from) == 0 || | |
333 (Z_STRLEN_P(from) == 1 && Z_STRVAL_P(from)[0] == '0')) { | |
334 *to = 0; | |
335 } else { | |
336 *to = 1; | |
337 } | |
338 } break; | |
339 default: { | |
340 zend_error(E_USER_ERROR, "Given value cannot be converted to bool."); | |
341 return false; | |
342 } | |
343 } | |
344 return true; | |
345 } | |
346 | |
347 bool protobuf_convert_to_string(zval* from) { | |
348 switch (Z_TYPE_P(from)) { | |
349 case IS_STRING: { | |
350 return true; | |
351 } | |
352 case IS_BOOL: | |
353 case IS_LONG: | |
354 case IS_DOUBLE: { | |
355 int use_copy; | |
356 zval tmp; | |
357 zend_make_printable_zval(from, &tmp, &use_copy); | |
358 ZVAL_COPY_VALUE(from, &tmp); | |
359 return true; | |
360 } | |
361 default: | |
362 zend_error(E_USER_ERROR, "Given value cannot be converted to string."); | |
363 return false; | |
364 } | |
365 } | |
366 | |
367 // ----------------------------------------------------------------------------- | |
368 // PHP Functions. | |
369 // ----------------------------------------------------------------------------- | |
370 | |
371 // The implementation of type checking for primitive fields is empty. This is | |
372 // because type checking is done when direct assigning message fields (e.g., | |
373 // foo->a = 1). Functions defined here are place holders in generated code for | |
374 // pure PHP implementation (c extension and pure PHP share the same generated | |
375 // code). | |
376 #define PHP_TYPE_CHECK(type) \ | |
377 PHP_METHOD(Util, check##type) {} | |
378 | |
379 PHP_TYPE_CHECK(Int32) | |
380 PHP_TYPE_CHECK(Uint32) | |
381 PHP_TYPE_CHECK(Int64) | |
382 PHP_TYPE_CHECK(Uint64) | |
383 PHP_TYPE_CHECK(Enum) | |
384 PHP_TYPE_CHECK(Float) | |
385 PHP_TYPE_CHECK(Double) | |
386 PHP_TYPE_CHECK(Bool) | |
387 PHP_TYPE_CHECK(String) | |
388 PHP_TYPE_CHECK(Bytes) | |
389 | |
390 #undef PHP_TYPE_CHECK | |
391 | |
392 PHP_METHOD(Util, checkMessage) { | |
393 zval* val; | |
394 zend_class_entry* klass = NULL; | |
395 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o!C", &val, &klass) == | |
396 FAILURE) { | |
397 return; | |
398 } | |
399 if (val == NULL) { | |
400 RETURN_NULL(); | |
401 } | |
402 if (!instanceof_function(Z_OBJCE_P(val), klass TSRMLS_CC)) { | |
403 zend_error(E_USER_ERROR, "Given value is not an instance of %s.", | |
404 klass->name); | |
405 return; | |
406 } | |
407 RETURN_ZVAL(val, 1, 0); | |
408 } | |
409 | |
410 PHP_METHOD(Util, checkRepeatedField) { | |
411 zval* val; | |
412 long type; | |
413 const zend_class_entry* klass = NULL; | |
414 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol|C", &val, | |
415 repeated_field_type, &type, &klass) == FAILURE) { | |
416 return; | |
417 } | |
418 | |
419 RepeatedField *intern = | |
420 (RepeatedField *)zend_object_store_get_object(val TSRMLS_CC); | |
421 if (to_fieldtype(type) != intern->type) { | |
422 zend_error(E_USER_ERROR, "Incorrect repeated field type."); | |
423 return; | |
424 } | |
425 if (klass != NULL && intern->msg_ce != klass) { | |
426 zend_error(E_USER_ERROR, "Expect a repeated field of %s, but %s is given.", | |
427 klass->name, intern->msg_ce->name); | |
428 return; | |
429 } | |
430 } | |
OLD | NEW |