| Index: third_party/protobuf/php/ext/google/protobuf/type_check.c
|
| diff --git a/third_party/protobuf/php/ext/google/protobuf/type_check.c b/third_party/protobuf/php/ext/google/protobuf/type_check.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d12d002584829aad8674c223a4d078fa73873b65
|
| --- /dev/null
|
| +++ b/third_party/protobuf/php/ext/google/protobuf/type_check.c
|
| @@ -0,0 +1,430 @@
|
| +// Protocol Buffers - Google's data interchange format
|
| +// Copyright 2008 Google Inc. All rights reserved.
|
| +// https://developers.google.com/protocol-buffers/
|
| +//
|
| +// Redistribution and use in source and binary forms, with or without
|
| +// modification, are permitted provided that the following conditions are
|
| +// met:
|
| +//
|
| +// * Redistributions of source code must retain the above copyright
|
| +// notice, this list of conditions and the following disclaimer.
|
| +// * Redistributions in binary form must reproduce the above
|
| +// copyright notice, this list of conditions and the following disclaimer
|
| +// in the documentation and/or other materials provided with the
|
| +// distribution.
|
| +// * Neither the name of Google Inc. nor the names of its
|
| +// contributors may be used to endorse or promote products derived from
|
| +// this software without specific prior written permission.
|
| +//
|
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| +
|
| +#include <Zend/zend_operators.h>
|
| +
|
| +#include "protobuf.h"
|
| +#include "utf8.h"
|
| +
|
| +static zend_class_entry* util_type;
|
| +static const char int64_min_digits[] = "9223372036854775808";
|
| +
|
| +ZEND_BEGIN_ARG_INFO_EX(arg_check_optional, 0, 0, 1)
|
| + ZEND_ARG_INFO(1, val)
|
| +ZEND_END_ARG_INFO()
|
| +
|
| +ZEND_BEGIN_ARG_INFO_EX(arg_check_message, 0, 0, 2)
|
| + ZEND_ARG_INFO(1, val)
|
| + ZEND_ARG_INFO(0, klass)
|
| +ZEND_END_ARG_INFO()
|
| +
|
| +ZEND_BEGIN_ARG_INFO_EX(arg_check_repeated, 0, 0, 2)
|
| + ZEND_ARG_INFO(1, val)
|
| + ZEND_ARG_INFO(0, type)
|
| + ZEND_ARG_INFO(0, klass)
|
| +ZEND_END_ARG_INFO()
|
| +
|
| +static zend_function_entry util_methods[] = {
|
| + PHP_ME(Util, checkInt32, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
| + PHP_ME(Util, checkUint32, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
| + PHP_ME(Util, checkInt64, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
| + PHP_ME(Util, checkUint64, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
| + PHP_ME(Util, checkEnum, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
| + PHP_ME(Util, checkFloat, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
| + PHP_ME(Util, checkDouble, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
| + PHP_ME(Util, checkBool, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
| + PHP_ME(Util, checkString, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
| + PHP_ME(Util, checkBytes, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
| + PHP_ME(Util, checkMessage, arg_check_message, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
| + PHP_ME(Util, checkRepeatedField, arg_check_repeated,
|
| + ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
| + ZEND_FE_END
|
| +};
|
| +
|
| +void util_init(TSRMLS_D) {
|
| + zend_class_entry class_type;
|
| + INIT_CLASS_ENTRY(class_type, "Google\\Protobuf\\Internal\\GPBUtil",
|
| + util_methods);
|
| + util_type = zend_register_internal_class(&class_type TSRMLS_CC);
|
| +}
|
| +
|
| +// -----------------------------------------------------------------------------
|
| +// Type checking/conversion.
|
| +// -----------------------------------------------------------------------------
|
| +
|
| +// This is modified from is_numeric_string in zend_operators.h. The behavior of
|
| +// this function is the same as is_numeric_string, except that this takes
|
| +// int64_t as input instead of long.
|
| +static zend_uchar convert_numeric_string(
|
| + const char *str, int length, int64_t *lval, double *dval) {
|
| + const char *ptr;
|
| + int base = 10, digits = 0, dp_or_e = 0;
|
| + double local_dval = 0.0;
|
| + zend_uchar type;
|
| +
|
| + if (length == 0) {
|
| + return IS_NULL;
|
| + }
|
| +
|
| + while (*str == ' ' || *str == '\t' || *str == '\n' ||
|
| + *str == '\r' || *str == '\v' || *str == '\f') {
|
| + str++;
|
| + length--;
|
| + }
|
| + ptr = str;
|
| +
|
| + if (*ptr == '-' || *ptr == '+') {
|
| + ptr++;
|
| + }
|
| +
|
| + if (ZEND_IS_DIGIT(*ptr)) {
|
| + // Handle hex numbers
|
| + // str is used instead of ptr to disallow signs and keep old behavior.
|
| + if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) {
|
| + base = 16;
|
| + ptr += 2;
|
| + }
|
| +
|
| + // Skip any leading 0s.
|
| + while (*ptr == '0') {
|
| + ptr++;
|
| + }
|
| +
|
| + // Count the number of digits. If a decimal point/exponent is found,
|
| + // it's a double. Otherwise, if there's a dval or no need to check for
|
| + // a full match, stop when there are too many digits for a int64 */
|
| + for (type = IS_LONG;
|
| + !(digits >= MAX_LENGTH_OF_INT64 && dval);
|
| + digits++, ptr++) {
|
| +check_digits:
|
| + if (ZEND_IS_DIGIT(*ptr) || (base == 16 && ZEND_IS_XDIGIT(*ptr))) {
|
| + continue;
|
| + } else if (base == 10) {
|
| + if (*ptr == '.' && dp_or_e < 1) {
|
| + goto process_double;
|
| + } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
|
| + const char *e = ptr + 1;
|
| +
|
| + if (*e == '-' || *e == '+') {
|
| + ptr = e++;
|
| + }
|
| + if (ZEND_IS_DIGIT(*e)) {
|
| + goto process_double;
|
| + }
|
| + }
|
| + }
|
| + break;
|
| + }
|
| +
|
| + if (base == 10) {
|
| + if (digits >= MAX_LENGTH_OF_INT64) {
|
| + dp_or_e = -1;
|
| + goto process_double;
|
| + }
|
| + } else if (!(digits < SIZEOF_INT64 * 2 ||
|
| + (digits == SIZEOF_INT64 * 2 && ptr[-digits] <= '7'))) {
|
| + if (dval) {
|
| + local_dval = zend_hex_strtod(str, &ptr);
|
| + }
|
| + type = IS_DOUBLE;
|
| + }
|
| + } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
|
| +process_double:
|
| + type = IS_DOUBLE;
|
| +
|
| + // If there's a dval, do the conversion; else continue checking
|
| + // the digits if we need to check for a full match.
|
| + if (dval) {
|
| + local_dval = zend_strtod(str, &ptr);
|
| + } else if (dp_or_e != -1) {
|
| + dp_or_e = (*ptr++ == '.') ? 1 : 2;
|
| + goto check_digits;
|
| + }
|
| + } else {
|
| + return IS_NULL;
|
| + }
|
| + if (ptr != str + length) {
|
| + zend_error(E_NOTICE, "A non well formed numeric value encountered");
|
| + return 0;
|
| + }
|
| +
|
| + if (type == IS_LONG) {
|
| + if (digits == MAX_LENGTH_OF_INT64 - 1) {
|
| + int cmp = strcmp(&ptr[-digits], int64_min_digits);
|
| +
|
| + if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
|
| + if (dval) {
|
| + *dval = zend_strtod(str, NULL);
|
| + }
|
| +
|
| + return IS_DOUBLE;
|
| + }
|
| + }
|
| + if (lval) {
|
| + *lval = strtoll(str, NULL, base);
|
| + }
|
| + return IS_LONG;
|
| + } else {
|
| + if (dval) {
|
| + *dval = local_dval;
|
| + }
|
| + return IS_DOUBLE;
|
| + }
|
| +}
|
| +
|
| +#define CONVERT_TO_INTEGER(type) \
|
| + static bool convert_int64_to_##type(int64_t val, type##_t* type##_value) { \
|
| + *type##_value = (type##_t)val; \
|
| + return true; \
|
| + } \
|
| + \
|
| + static bool convert_double_to_##type(double val, type##_t* type##_value) { \
|
| + *type##_value = (type##_t)zend_dval_to_lval(val); \
|
| + return true; \
|
| + } \
|
| + \
|
| + static bool convert_string_to_##type(const char* val, int len, \
|
| + type##_t* type##_value) { \
|
| + int64_t lval; \
|
| + double dval; \
|
| + \
|
| + switch (convert_numeric_string(val, len, &lval, &dval)) { \
|
| + case IS_DOUBLE: { \
|
| + return convert_double_to_##type(dval, type##_value); \
|
| + } \
|
| + case IS_LONG: { \
|
| + return convert_int64_to_##type(lval, type##_value); \
|
| + } \
|
| + default: \
|
| + zend_error(E_USER_ERROR, \
|
| + "Given string value cannot be converted to integer."); \
|
| + return false; \
|
| + } \
|
| + } \
|
| + \
|
| + bool protobuf_convert_to_##type(zval* from, type##_t* to) { \
|
| + switch (Z_TYPE_P(from)) { \
|
| + case IS_LONG: { \
|
| + return convert_int64_to_##type(Z_LVAL_P(from), to); \
|
| + } \
|
| + case IS_DOUBLE: { \
|
| + return convert_double_to_##type(Z_DVAL_P(from), to); \
|
| + } \
|
| + case IS_STRING: { \
|
| + return convert_string_to_##type(Z_STRVAL_P(from), Z_STRLEN_P(from), \
|
| + to); \
|
| + } \
|
| + default: { \
|
| + zend_error(E_USER_ERROR, \
|
| + "Given value cannot be converted to integer."); \
|
| + return false; \
|
| + } \
|
| + } \
|
| + return false; \
|
| + }
|
| +
|
| +CONVERT_TO_INTEGER(int32);
|
| +CONVERT_TO_INTEGER(uint32);
|
| +CONVERT_TO_INTEGER(int64);
|
| +CONVERT_TO_INTEGER(uint64);
|
| +
|
| +#undef CONVERT_TO_INTEGER
|
| +
|
| +#define CONVERT_TO_FLOAT(type) \
|
| + static bool convert_int64_to_##type(int64_t val, type* type##_value) { \
|
| + *type##_value = (type)val; \
|
| + return true; \
|
| + } \
|
| + \
|
| + static bool convert_double_to_##type(double val, type* type##_value) { \
|
| + *type##_value = (type)val; \
|
| + return true; \
|
| + } \
|
| + \
|
| + static bool convert_string_to_##type(const char* val, int len, \
|
| + type* type##_value) { \
|
| + int64_t lval; \
|
| + double dval; \
|
| + \
|
| + switch (convert_numeric_string(val, len, &lval, &dval)) { \
|
| + case IS_DOUBLE: { \
|
| + *type##_value = (type)dval; \
|
| + return true; \
|
| + } \
|
| + case IS_LONG: { \
|
| + *type##_value = (type)lval; \
|
| + return true; \
|
| + } \
|
| + default: \
|
| + zend_error(E_USER_ERROR, \
|
| + "Given string value cannot be converted to integer."); \
|
| + return false; \
|
| + } \
|
| + } \
|
| + \
|
| + bool protobuf_convert_to_##type(zval* from, type* to) { \
|
| + switch (Z_TYPE_P(from)) { \
|
| + case IS_LONG: { \
|
| + return convert_int64_to_##type(Z_LVAL_P(from), to); \
|
| + } \
|
| + case IS_DOUBLE: { \
|
| + return convert_double_to_##type(Z_DVAL_P(from), to); \
|
| + } \
|
| + case IS_STRING: { \
|
| + return convert_string_to_##type(Z_STRVAL_P(from), Z_STRLEN_P(from), \
|
| + to); \
|
| + } \
|
| + default: { \
|
| + zend_error(E_USER_ERROR, \
|
| + "Given value cannot be converted to integer."); \
|
| + return false; \
|
| + } \
|
| + } \
|
| + return false; \
|
| + }
|
| +
|
| +CONVERT_TO_FLOAT(float);
|
| +CONVERT_TO_FLOAT(double);
|
| +
|
| +#undef CONVERT_TO_FLOAT
|
| +
|
| +bool protobuf_convert_to_bool(zval* from, int8_t* to) {
|
| + switch (Z_TYPE_P(from)) {
|
| + case IS_BOOL:
|
| + *to = (int8_t)Z_BVAL_P(from);
|
| + break;
|
| + case IS_LONG:
|
| + *to = (int8_t)(Z_LVAL_P(from) != 0);
|
| + break;
|
| + case IS_DOUBLE:
|
| + *to = (int8_t)(Z_LVAL_P(from) != 0);
|
| + break;
|
| + case IS_STRING: {
|
| + char* strval = Z_STRVAL_P(from);
|
| +
|
| + if (Z_STRLEN_P(from) == 0 ||
|
| + (Z_STRLEN_P(from) == 1 && Z_STRVAL_P(from)[0] == '0')) {
|
| + *to = 0;
|
| + } else {
|
| + *to = 1;
|
| + }
|
| + } break;
|
| + default: {
|
| + zend_error(E_USER_ERROR, "Given value cannot be converted to bool.");
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool protobuf_convert_to_string(zval* from) {
|
| + switch (Z_TYPE_P(from)) {
|
| + case IS_STRING: {
|
| + return true;
|
| + }
|
| + case IS_BOOL:
|
| + case IS_LONG:
|
| + case IS_DOUBLE: {
|
| + int use_copy;
|
| + zval tmp;
|
| + zend_make_printable_zval(from, &tmp, &use_copy);
|
| + ZVAL_COPY_VALUE(from, &tmp);
|
| + return true;
|
| + }
|
| + default:
|
| + zend_error(E_USER_ERROR, "Given value cannot be converted to string.");
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +// -----------------------------------------------------------------------------
|
| +// PHP Functions.
|
| +// -----------------------------------------------------------------------------
|
| +
|
| +// The implementation of type checking for primitive fields is empty. This is
|
| +// because type checking is done when direct assigning message fields (e.g.,
|
| +// foo->a = 1). Functions defined here are place holders in generated code for
|
| +// pure PHP implementation (c extension and pure PHP share the same generated
|
| +// code).
|
| +#define PHP_TYPE_CHECK(type) \
|
| + PHP_METHOD(Util, check##type) {}
|
| +
|
| +PHP_TYPE_CHECK(Int32)
|
| +PHP_TYPE_CHECK(Uint32)
|
| +PHP_TYPE_CHECK(Int64)
|
| +PHP_TYPE_CHECK(Uint64)
|
| +PHP_TYPE_CHECK(Enum)
|
| +PHP_TYPE_CHECK(Float)
|
| +PHP_TYPE_CHECK(Double)
|
| +PHP_TYPE_CHECK(Bool)
|
| +PHP_TYPE_CHECK(String)
|
| +PHP_TYPE_CHECK(Bytes)
|
| +
|
| +#undef PHP_TYPE_CHECK
|
| +
|
| +PHP_METHOD(Util, checkMessage) {
|
| + zval* val;
|
| + zend_class_entry* klass = NULL;
|
| + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o!C", &val, &klass) ==
|
| + FAILURE) {
|
| + return;
|
| + }
|
| + if (val == NULL) {
|
| + RETURN_NULL();
|
| + }
|
| + if (!instanceof_function(Z_OBJCE_P(val), klass TSRMLS_CC)) {
|
| + zend_error(E_USER_ERROR, "Given value is not an instance of %s.",
|
| + klass->name);
|
| + return;
|
| + }
|
| + RETURN_ZVAL(val, 1, 0);
|
| +}
|
| +
|
| +PHP_METHOD(Util, checkRepeatedField) {
|
| + zval* val;
|
| + long type;
|
| + const zend_class_entry* klass = NULL;
|
| + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol|C", &val,
|
| + repeated_field_type, &type, &klass) == FAILURE) {
|
| + return;
|
| + }
|
| +
|
| + RepeatedField *intern =
|
| + (RepeatedField *)zend_object_store_get_object(val TSRMLS_CC);
|
| + if (to_fieldtype(type) != intern->type) {
|
| + zend_error(E_USER_ERROR, "Incorrect repeated field type.");
|
| + return;
|
| + }
|
| + if (klass != NULL && intern->msg_ce != klass) {
|
| + zend_error(E_USER_ERROR, "Expect a repeated field of %s, but %s is given.",
|
| + klass->name, intern->msg_ce->name);
|
| + return;
|
| + }
|
| +}
|
|
|