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 |