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; |
+ } |
+} |