| 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 |