| OLD | NEW |
| 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 #ifndef __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ | 1 #ifndef __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ |
| 32 #define __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ | 2 #define __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ |
| 33 | 3 |
| 34 #include <php.h> | 4 #include <php.h> |
| 35 | 5 |
| 36 // ubp.h has to be placed after php.h. Othwise, php.h will introduce NDEBUG. | |
| 37 #include "upb.h" | 6 #include "upb.h" |
| 38 | 7 |
| 39 #define PHP_PROTOBUF_EXTNAME "protobuf" | 8 #define PHP_PROTOBUF_EXTNAME "protobuf" |
| 40 #define PHP_PROTOBUF_VERSION "3.1.0a1" | 9 #define PHP_PROTOBUF_VERSION "0.01" |
| 41 | 10 |
| 42 #define MAX_LENGTH_OF_INT64 20 | 11 // Forward decls. |
| 43 #define SIZEOF_INT64 8 | |
| 44 | |
| 45 // ----------------------------------------------------------------------------- | |
| 46 // Forward Declaration | |
| 47 // ---------------------------------------------------------------------------- | |
| 48 | |
| 49 struct DescriptorPool; | 12 struct DescriptorPool; |
| 50 struct Descriptor; | 13 struct Descriptor; |
| 14 struct FieldDescriptor; |
| 51 struct EnumDescriptor; | 15 struct EnumDescriptor; |
| 52 struct FieldDescriptor; | 16 struct MessageLayout; |
| 53 struct MessageField; | 17 struct MessageField; |
| 54 struct MessageHeader; | 18 struct MessageHeader; |
| 55 struct MessageLayout; | 19 struct MessageBuilderContext; |
| 56 struct RepeatedField; | 20 struct EnumBuilderContext; |
| 57 struct RepeatedFieldIter; | |
| 58 struct MapField; | |
| 59 | 21 |
| 60 typedef struct DescriptorPool DescriptorPool; | 22 typedef struct DescriptorPool DescriptorPool; |
| 61 typedef struct Descriptor Descriptor; | 23 typedef struct Descriptor Descriptor; |
| 24 typedef struct FieldDescriptor FieldDescriptor; |
| 25 typedef struct OneofDescriptor OneofDescriptor; |
| 62 typedef struct EnumDescriptor EnumDescriptor; | 26 typedef struct EnumDescriptor EnumDescriptor; |
| 63 typedef struct FieldDescriptor FieldDescriptor; | 27 typedef struct MessageLayout MessageLayout; |
| 64 typedef struct MessageField MessageField; | 28 typedef struct MessageField MessageField; |
| 65 typedef struct MessageHeader MessageHeader; | 29 typedef struct MessageHeader MessageHeader; |
| 66 typedef struct MessageLayout MessageLayout; | 30 typedef struct MessageBuilderContext MessageBuilderContext; |
| 67 typedef struct RepeatedField RepeatedField; | 31 typedef struct OneofBuilderContext OneofBuilderContext; |
| 68 typedef struct RepeatedFieldIter RepeatedFieldIter; | 32 typedef struct EnumBuilderContext EnumBuilderContext; |
| 69 typedef struct MapField MapField; | 33 |
| 34 extern zend_class_entry* builder_type; |
| 35 extern zend_class_entry* descriptor_type; |
| 36 extern zend_class_entry* message_builder_context_type; |
| 37 |
| 38 extern DescriptorPool* generated_pool; // The actual generated pool |
| 39 |
| 40 ZEND_BEGIN_MODULE_GLOBALS(protobuf) |
| 41 zval* generated_pool; |
| 42 zend_object_handlers* message_handlers; |
| 43 HashTable upb_def_to_php_obj_map; |
| 44 ZEND_END_MODULE_GLOBALS(protobuf) |
| 45 |
| 46 ZEND_DECLARE_MODULE_GLOBALS(protobuf) |
| 47 |
| 48 #ifdef ZTS |
| 49 #define PROTOBUF_G(v) TSRMG(protobuf_globals_id, zend_protobuf_globals*, v) |
| 50 #else |
| 51 #define PROTOBUF_G(v) (protobuf_globals.v) |
| 52 #endif |
| 70 | 53 |
| 71 // ----------------------------------------------------------------------------- | 54 // ----------------------------------------------------------------------------- |
| 72 // Globals. | 55 // PHP functions and global variables. |
| 73 // ----------------------------------------------------------------------------- | 56 // ----------------------------------------------------------------------------- |
| 74 | 57 |
| 75 ZEND_BEGIN_MODULE_GLOBALS(protobuf) | 58 PHP_MINIT_FUNCTION(protobuf); |
| 76 ZEND_END_MODULE_GLOBALS(protobuf) | |
| 77 | |
| 78 // Init module and PHP classes. | |
| 79 void descriptor_init(TSRMLS_D); | |
| 80 void enum_descriptor_init(TSRMLS_D); | |
| 81 void descriptor_pool_init(TSRMLS_D); | |
| 82 void gpb_type_init(TSRMLS_D); | |
| 83 void map_field_init(TSRMLS_D); | |
| 84 void repeated_field_init(TSRMLS_D); | |
| 85 void repeated_field_iter_init(TSRMLS_D); | |
| 86 void util_init(TSRMLS_D); | |
| 87 void message_init(TSRMLS_D); | |
| 88 | |
| 89 // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor | |
| 90 // instances. | |
| 91 void add_def_obj(const void* def, zval* value); | |
| 92 zval* get_def_obj(const void* def); | |
| 93 | |
| 94 // Global map from PHP class entries to wrapper Descriptor/EnumDescriptor | |
| 95 // instances. | |
| 96 void add_ce_obj(const void* ce, zval* value); | |
| 97 zval* get_ce_obj(const void* ce); | |
| 98 | |
| 99 extern zend_class_entry* map_field_type; | |
| 100 extern zend_class_entry* repeated_field_type; | |
| 101 | 59 |
| 102 // ----------------------------------------------------------------------------- | 60 // ----------------------------------------------------------------------------- |
| 103 // Descriptor. | 61 // PHP class structure. |
| 104 // ----------------------------------------------------------------------------- | 62 // ----------------------------------------------------------------------------- |
| 105 | 63 |
| 106 struct DescriptorPool { | 64 struct DescriptorPool { |
| 107 zend_object std; | 65 zend_object std; |
| 108 upb_symtab* symtab; | 66 upb_symtab* symtab; |
| 109 HashTable* pending_list; | 67 HashTable* pending_list; |
| 110 }; | 68 }; |
| 111 | 69 |
| 112 PHP_METHOD(DescriptorPool, getGeneratedPool); | |
| 113 PHP_METHOD(DescriptorPool, internalAddGeneratedFile); | |
| 114 | |
| 115 extern zval* generated_pool_php; // wrapper of generated pool | |
| 116 extern DescriptorPool* generated_pool; // The actual generated pool | |
| 117 | |
| 118 struct Descriptor { | 70 struct Descriptor { |
| 119 zend_object std; | 71 zend_object std; |
| 120 const upb_msgdef* msgdef; | 72 const upb_msgdef* msgdef; |
| 121 MessageLayout* layout; | 73 MessageLayout* layout; |
| 122 zend_class_entry* klass; // begins as NULL | 74 // zval* klass; // begins as NULL |
| 123 const upb_handlers* fill_handlers; | 75 // const upb_handlers* fill_handlers; |
| 124 const upb_pbdecodermethod* fill_method; | 76 // const upb_pbdecodermethod* fill_method; |
| 125 const upb_handlers* pb_serialize_handlers; | 77 const upb_handlers* pb_serialize_handlers; |
| 78 // const upb_handlers* json_serialize_handlers; |
| 79 // Handlers hold type class references for sub-message fields directly in some |
| 80 // cases. We need to keep these rooted because they might otherwise be |
| 81 // collected. |
| 82 // zval_array typeclass_references; |
| 126 }; | 83 }; |
| 127 | 84 |
| 128 extern zend_class_entry* descriptor_type; | |
| 129 | |
| 130 void descriptor_name_set(Descriptor *desc, const char *name); | |
| 131 | |
| 132 struct FieldDescriptor { | 85 struct FieldDescriptor { |
| 133 zend_object std; | 86 zend_object std; |
| 134 const upb_fielddef* fielddef; | 87 const upb_fielddef* fielddef; |
| 135 }; | 88 }; |
| 136 | 89 |
| 90 struct OneofDescriptor { |
| 91 zend_object std; |
| 92 const upb_oneofdef* oneofdef; |
| 93 }; |
| 94 |
| 137 struct EnumDescriptor { | 95 struct EnumDescriptor { |
| 138 zend_object std; | 96 zend_object std; |
| 139 const upb_enumdef* enumdef; | 97 const upb_enumdef* enumdef; |
| 140 zend_class_entry* klass; // begins as NULL | 98 // zval* module; // begins as NULL |
| 141 // VALUE module; // begins as nil | |
| 142 }; | 99 }; |
| 143 | 100 |
| 144 extern zend_class_entry* enum_descriptor_type; | |
| 145 | |
| 146 // ----------------------------------------------------------------------------- | 101 // ----------------------------------------------------------------------------- |
| 147 // Message class creation. | 102 // Native slot storage abstraction. |
| 148 // ----------------------------------------------------------------------------- | 103 // ----------------------------------------------------------------------------- |
| 149 | 104 |
| 150 void* message_data(void* msg); | 105 #define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t) |
| 151 | 106 |
| 152 // Build PHP class for given descriptor. Instead of building from scratch, this | 107 size_t native_slot_size(upb_fieldtype_t type); |
| 153 // function modifies existing class which has been partially defined in PHP | |
| 154 // code. | |
| 155 void build_class_from_descriptor(zval* php_descriptor TSRMLS_DC); | |
| 156 | 108 |
| 157 extern zend_object_handlers* message_handlers; | 109 #define MAP_KEY_FIELD 1 |
| 110 #define MAP_VALUE_FIELD 2 |
| 111 |
| 112 // Oneof case slot value to indicate that no oneof case is set. The value `0` is |
| 113 // safe because field numbers are used as case identifiers, and no field can |
| 114 // have a number of 0. |
| 115 #define ONEOF_CASE_NONE 0 |
| 116 |
| 117 // These operate on a map field (i.e., a repeated field of submessages whose |
| 118 // submessage type is a map-entry msgdef). |
| 119 bool is_map_field(const upb_fielddef* field); |
| 120 const upb_fielddef* map_field_key(const upb_fielddef* field); |
| 121 const upb_fielddef* map_field_value(const upb_fielddef* field); |
| 122 |
| 123 // These operate on a map-entry msgdef. |
| 124 const upb_fielddef* map_entry_key(const upb_msgdef* msgdef); |
| 125 const upb_fielddef* map_entry_value(const upb_msgdef* msgdef); |
| 158 | 126 |
| 159 // ----------------------------------------------------------------------------- | 127 // ----------------------------------------------------------------------------- |
| 160 // Message layout / storage. | 128 // Message layout / storage. |
| 161 // ----------------------------------------------------------------------------- | 129 // ----------------------------------------------------------------------------- |
| 162 | 130 |
| 163 /* | |
| 164 * In c extension, each protobuf message is a zval instance. The zval instance | |
| 165 * is like union, which can be used to store int, string, zend_object_value and | |
| 166 * etc. For protobuf message, the zval instance is used to store the | |
| 167 * zend_object_value. | |
| 168 * | |
| 169 * The zend_object_value is composed of handlers and a handle to look up the | |
| 170 * actual stored data. The handlers are pointers to functions, e.g., read, | |
| 171 * write, and etc, to access properties. | |
| 172 * | |
| 173 * The actual data of protobuf messages is stored as MessageHeader in zend | |
| 174 * engine's central repository. Each MessageHeader instance is composed of a | |
| 175 * zend_object, a Descriptor instance and the real message data. | |
| 176 * | |
| 177 * For the reason that PHP's native types may not be large enough to store | |
| 178 * protobuf message's field (e.g., int64), all message's data is stored in | |
| 179 * custom memory layout and is indexed by the Descriptor instance. | |
| 180 * | |
| 181 * The zend_object contains the zend class entry and the properties table. The | |
| 182 * zend class entry contains all information about protobuf message's | |
| 183 * corresponding PHP class. The most useful information is the offset table of | |
| 184 * properties. Because read access to properties requires returning zval | |
| 185 * instance, we need to convert data from the custom layout to zval instance. | |
| 186 * Instead of creating zval instance for every read access, we use the zval | |
| 187 * instances in the properties table in the zend_object as cache. When | |
| 188 * accessing properties, the offset is needed to find the zval property in | |
| 189 * zend_object's properties table. These properties will be updated using the | |
| 190 * data from custom memory layout only when reading these properties. | |
| 191 * | |
| 192 * zval | |
| 193 * |-zend_object_value obj | |
| 194 * |-zend_object_handlers* handlers -> |-read_property_handler | |
| 195 * | |-write_property_handler | |
| 196 * | ++++++++++++++++++++++ | |
| 197 * |-zend_object_handle handle -> + central repository + | |
| 198 * ++++++++++++++++++++++ | |
| 199 * MessageHeader <-----------------| | |
| 200 * |-zend_object std | |
| 201 * | |-class_entry* ce -> class_entry | |
| 202 * | | |-HashTable properties_table (name->offset) | |
| 203 * | |-zval** properties_table <------------------------------| | |
| 204 * | |------> zval* property(cache) | |
| 205 * |-Descriptor* desc (name->offset) | |
| 206 * |-void** data <-----------| | |
| 207 * |-----------------------> void* property(data) | |
| 208 * | |
| 209 */ | |
| 210 | |
| 211 #define MESSAGE_FIELD_NO_CASE ((size_t)-1) | 131 #define MESSAGE_FIELD_NO_CASE ((size_t)-1) |
| 212 | 132 |
| 213 struct MessageField { | 133 struct MessageField { |
| 214 size_t offset; | 134 size_t offset; |
| 215 int cache_index; // Each field except oneof field has a zval cache to avoid | 135 size_t case_offset; // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE. |
| 216 // multiple creation when being accessed. | |
| 217 size_t case_offset; // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE. | |
| 218 }; | 136 }; |
| 219 | 137 |
| 220 struct MessageLayout { | 138 struct MessageLayout { |
| 221 const upb_msgdef* msgdef; | 139 const upb_msgdef* msgdef; |
| 222 MessageField* fields; | 140 MessageField* fields; |
| 223 size_t size; | 141 size_t size; |
| 224 }; | 142 }; |
| 225 | 143 |
| 144 void layout_init(MessageLayout* layout, void* storage); |
| 145 zval* layout_get(MessageLayout* layout, const void* storage, |
| 146 const upb_fielddef* field TSRMLS_DC); |
| 147 MessageLayout* create_layout(const upb_msgdef* msgdef); |
| 148 void free_layout(MessageLayout* layout); |
| 149 zval* native_slot_get(upb_fieldtype_t type, /*VALUE type_class,*/ |
| 150 const void* memory TSRMLS_DC); |
| 151 |
| 152 // ----------------------------------------------------------------------------- |
| 153 // Message class creation. |
| 154 // ----------------------------------------------------------------------------- |
| 155 |
| 226 struct MessageHeader { | 156 struct MessageHeader { |
| 227 zend_object std; // Stores properties table and class info of PHP instance. | 157 zend_object std; |
| 228 // This is needed for MessageHeader to be accessed via PHP. | 158 Descriptor* descriptor; // kept alive by self.class.descriptor reference. |
| 229 Descriptor* descriptor; // Kept alive by self.class.descriptor reference. | 159 // Data comes after this. |
| 230 // The real message data is appended after MessageHeader. | |
| 231 }; | 160 }; |
| 232 | 161 |
| 233 MessageLayout* create_layout(const upb_msgdef* msgdef); | 162 struct MessageBuilderContext { |
| 234 void layout_init(MessageLayout* layout, void* storage, | 163 zend_object std; |
| 235 zval** properties_table TSRMLS_DC); | 164 zval* descriptor; |
| 236 zval* layout_get(MessageLayout* layout, const void* storage, | 165 zval* pool; |
| 237 const upb_fielddef* field, zval** cache TSRMLS_DC); | 166 }; |
| 238 void layout_set(MessageLayout* layout, MessageHeader* header, | |
| 239 const upb_fielddef* field, zval* val TSRMLS_DC); | |
| 240 void free_layout(MessageLayout* layout); | |
| 241 | 167 |
| 242 PHP_METHOD(Message, readOneof); | 168 struct OneofBuilderContext { |
| 243 PHP_METHOD(Message, writeOneof); | 169 zend_object std; |
| 244 PHP_METHOD(Message, __construct); | 170 // VALUE descriptor; |
| 171 // VALUE builder; |
| 172 }; |
| 173 |
| 174 struct EnumBuilderContext { |
| 175 zend_object std; |
| 176 // VALUE enumdesc; |
| 177 }; |
| 178 |
| 179 // Forward-declare all of the PHP method implementations. |
| 180 |
| 181 DescriptorPool* php_to_descriptor_pool(zval* value TSRMLS_DC); |
| 182 zend_object_value descriptor_pool_create(zend_class_entry *ce TSRMLS_DC); |
| 183 void descriptor_pool_free_c(DescriptorPool* object TSRMLS_DC); |
| 184 void descriptor_pool_free(void* object TSRMLS_DC); |
| 185 void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC); |
| 186 PHP_METHOD(DescriptorPool, addMessage); |
| 187 PHP_METHOD(DescriptorPool, finalize); |
| 188 |
| 189 Descriptor* php_to_descriptor(zval* value TSRMLS_DC); |
| 190 zend_object_value descriptor_create(zend_class_entry *ce TSRMLS_DC); |
| 191 void descriptor_init_c_instance(Descriptor* intern TSRMLS_DC); |
| 192 void descriptor_free_c(Descriptor* object TSRMLS_DC); |
| 193 void descriptor_free(void* object TSRMLS_DC); |
| 194 void descriptor_name_set(Descriptor *desc, const char *name); |
| 195 |
| 196 MessageBuilderContext* php_to_message_builder_context(zval* value TSRMLS_DC); |
| 197 zend_object_value message_builder_context_create( |
| 198 zend_class_entry* ce TSRMLS_DC); |
| 199 void message_builder_context_init_c_instance( |
| 200 MessageBuilderContext* intern TSRMLS_DC); |
| 201 void message_builder_context_free_c(MessageBuilderContext* object TSRMLS_DC); |
| 202 void message_builder_context_free(void* object TSRMLS_DC); |
| 203 PHP_METHOD(MessageBuilderContext, optional); |
| 204 PHP_METHOD(MessageBuilderContext, finalizeToPool); |
| 205 |
| 206 PHP_METHOD(Message, encode); |
| 207 const zend_class_entry* build_class_from_descriptor( |
| 208 zval* php_descriptor TSRMLS_DC); |
| 209 |
| 210 PHP_FUNCTION(get_generated_pool); |
| 245 | 211 |
| 246 // ----------------------------------------------------------------------------- | 212 // ----------------------------------------------------------------------------- |
| 247 // Encode / Decode. | 213 // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor |
| 248 // ----------------------------------------------------------------------------- | 214 // instances. |
| 215 // ---------------------------------------------------------------------------- |
| 249 | 216 |
| 250 // Maximum depth allowed during encoding, to avoid stack overflows due to | 217 void add_def_obj(const void* def, zval* value); |
| 251 // cycles. | 218 zval* get_def_obj(const void* def); |
| 252 #define ENCODE_MAX_NESTING 63 | |
| 253 | |
| 254 // Constructs the upb decoder method for parsing messages of this type. | |
| 255 // This is called from the message class creation code. | |
| 256 const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor *desc, | |
| 257 const void *owner); | |
| 258 | |
| 259 PHP_METHOD(Message, encode); | |
| 260 PHP_METHOD(Message, decode); | |
| 261 | |
| 262 // ----------------------------------------------------------------------------- | |
| 263 // Type check / conversion. | |
| 264 // ----------------------------------------------------------------------------- | |
| 265 | |
| 266 bool protobuf_convert_to_int32(zval* from, int32_t* to); | |
| 267 bool protobuf_convert_to_uint32(zval* from, uint32_t* to); | |
| 268 bool protobuf_convert_to_int64(zval* from, int64_t* to); | |
| 269 bool protobuf_convert_to_uint64(zval* from, uint64_t* to); | |
| 270 bool protobuf_convert_to_float(zval* from, float* to); | |
| 271 bool protobuf_convert_to_double(zval* from, double* to); | |
| 272 bool protobuf_convert_to_bool(zval* from, int8_t* to); | |
| 273 bool protobuf_convert_to_string(zval* from); | |
| 274 | |
| 275 PHP_METHOD(Util, checkInt32); | |
| 276 PHP_METHOD(Util, checkUint32); | |
| 277 PHP_METHOD(Util, checkInt64); | |
| 278 PHP_METHOD(Util, checkUint64); | |
| 279 PHP_METHOD(Util, checkEnum); | |
| 280 PHP_METHOD(Util, checkFloat); | |
| 281 PHP_METHOD(Util, checkDouble); | |
| 282 PHP_METHOD(Util, checkBool); | |
| 283 PHP_METHOD(Util, checkString); | |
| 284 PHP_METHOD(Util, checkBytes); | |
| 285 PHP_METHOD(Util, checkMessage); | |
| 286 PHP_METHOD(Util, checkRepeatedField); | |
| 287 | |
| 288 // ----------------------------------------------------------------------------- | |
| 289 // Native slot storage abstraction. | |
| 290 // ----------------------------------------------------------------------------- | |
| 291 | |
| 292 #define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t) | |
| 293 | |
| 294 size_t native_slot_size(upb_fieldtype_t type); | |
| 295 bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass, | |
| 296 void* memory, zval* value TSRMLS_DC); | |
| 297 void native_slot_init(upb_fieldtype_t type, void* memory, zval** cache); | |
| 298 // For each property, in order to avoid conversion between the zval object and | |
| 299 // the actual data type during parsing/serialization, the containing message | |
| 300 // object use the custom memory layout to store the actual data type for each | |
| 301 // property inside of it. To access a property from php code, the property | |
| 302 // needs to be converted to a zval object. The message object is not responsible | |
| 303 // for providing such a zval object. Instead the caller needs to provide one | |
| 304 // (cache) and update it with the actual data (memory). | |
| 305 void native_slot_get(upb_fieldtype_t type, const void* memory, | |
| 306 zval** cache TSRMLS_DC); | |
| 307 void native_slot_get_default(upb_fieldtype_t type, zval** cache TSRMLS_DC); | |
| 308 | |
| 309 // ----------------------------------------------------------------------------- | |
| 310 // Map Field. | |
| 311 // ----------------------------------------------------------------------------- | |
| 312 | |
| 313 extern zend_object_handlers* map_field_handlers; | |
| 314 | |
| 315 typedef struct { | |
| 316 zend_object std; | |
| 317 upb_fieldtype_t key_type; | |
| 318 upb_fieldtype_t value_type; | |
| 319 const zend_class_entry* msg_ce; // class entry for value message | |
| 320 upb_strtable table; | |
| 321 } Map; | |
| 322 | |
| 323 typedef struct { | |
| 324 Map* self; | |
| 325 upb_strtable_iter it; | |
| 326 } MapIter; | |
| 327 | |
| 328 void map_begin(zval* self, MapIter* iter TSRMLS_DC); | |
| 329 void map_next(MapIter* iter); | |
| 330 bool map_done(MapIter* iter); | |
| 331 const char* map_iter_key(MapIter* iter, int* len); | |
| 332 upb_value map_iter_value(MapIter* iter, int* len); | |
| 333 | |
| 334 // These operate on a map-entry msgdef. | |
| 335 const upb_fielddef* map_entry_key(const upb_msgdef* msgdef); | |
| 336 const upb_fielddef* map_entry_value(const upb_msgdef* msgdef); | |
| 337 | |
| 338 zend_object_value map_field_create(zend_class_entry *ce TSRMLS_DC); | |
| 339 void map_field_create_with_type(zend_class_entry *ce, const upb_fielddef *field, | |
| 340 zval **map_field TSRMLS_DC); | |
| 341 void map_field_free(void* object TSRMLS_DC); | |
| 342 void* upb_value_memory(upb_value* v); | |
| 343 | |
| 344 #define MAP_KEY_FIELD 1 | |
| 345 #define MAP_VALUE_FIELD 2 | |
| 346 | |
| 347 // These operate on a map field (i.e., a repeated field of submessages whose | |
| 348 // submessage type is a map-entry msgdef). | |
| 349 bool is_map_field(const upb_fielddef* field); | |
| 350 const upb_fielddef* map_field_key(const upb_fielddef* field); | |
| 351 const upb_fielddef* map_field_value(const upb_fielddef* field); | |
| 352 | |
| 353 bool map_index_set(Map *intern, const char* keyval, int length, upb_value v); | |
| 354 | |
| 355 PHP_METHOD(MapField, __construct); | |
| 356 PHP_METHOD(MapField, offsetExists); | |
| 357 PHP_METHOD(MapField, offsetGet); | |
| 358 PHP_METHOD(MapField, offsetSet); | |
| 359 PHP_METHOD(MapField, offsetUnset); | |
| 360 PHP_METHOD(MapField, count); | |
| 361 | |
| 362 // ----------------------------------------------------------------------------- | |
| 363 // Repeated Field. | |
| 364 // ----------------------------------------------------------------------------- | |
| 365 | |
| 366 extern zend_object_handlers* repeated_field_handlers; | |
| 367 | |
| 368 struct RepeatedField { | |
| 369 zend_object std; | |
| 370 zval* array; | |
| 371 upb_fieldtype_t type; | |
| 372 const zend_class_entry* msg_ce; // class entry for containing message | |
| 373 // (for message field only). | |
| 374 }; | |
| 375 | |
| 376 struct RepeatedFieldIter { | |
| 377 zend_object std; | |
| 378 RepeatedField* repeated_field; | |
| 379 long position; | |
| 380 }; | |
| 381 | |
| 382 void repeated_field_create_with_type(zend_class_entry* ce, | |
| 383 const upb_fielddef* field, | |
| 384 zval** repeated_field TSRMLS_DC); | |
| 385 // Return the element at the index position from the repeated field. There is | |
| 386 // not restriction on the type of stored elements. | |
| 387 void *repeated_field_index_native(RepeatedField *intern, int index TSRMLS_DC); | |
| 388 // Add the element to the end of the repeated field. There is not restriction on | |
| 389 // the type of stored elements. | |
| 390 void repeated_field_push_native(RepeatedField *intern, void *value TSRMLS_DC); | |
| 391 | |
| 392 PHP_METHOD(RepeatedField, __construct); | |
| 393 PHP_METHOD(RepeatedField, append); | |
| 394 PHP_METHOD(RepeatedField, offsetExists); | |
| 395 PHP_METHOD(RepeatedField, offsetGet); | |
| 396 PHP_METHOD(RepeatedField, offsetSet); | |
| 397 PHP_METHOD(RepeatedField, offsetUnset); | |
| 398 PHP_METHOD(RepeatedField, count); | |
| 399 PHP_METHOD(RepeatedField, getIterator); | |
| 400 | |
| 401 PHP_METHOD(RepeatedFieldIter, rewind); | |
| 402 PHP_METHOD(RepeatedFieldIter, current); | |
| 403 PHP_METHOD(RepeatedFieldIter, key); | |
| 404 PHP_METHOD(RepeatedFieldIter, next); | |
| 405 PHP_METHOD(RepeatedFieldIter, valid); | |
| 406 | |
| 407 // ----------------------------------------------------------------------------- | |
| 408 // Oneof Field. | |
| 409 // ----------------------------------------------------------------------------- | |
| 410 | |
| 411 typedef struct { | |
| 412 zend_object std; | |
| 413 upb_oneofdef* oneofdef; | |
| 414 int index; // Index of field in oneof. -1 if not set. | |
| 415 char value[NATIVE_SLOT_MAX_SIZE]; | |
| 416 } Oneof; | |
| 417 | |
| 418 // Oneof case slot value to indicate that no oneof case is set. The value `0` is | |
| 419 // safe because field numbers are used as case identifiers, and no field can | |
| 420 // have a number of 0. | |
| 421 #define ONEOF_CASE_NONE 0 | |
| 422 | |
| 423 // ----------------------------------------------------------------------------- | |
| 424 // Upb. | |
| 425 // ----------------------------------------------------------------------------- | |
| 426 | |
| 427 upb_fieldtype_t to_fieldtype(upb_descriptortype_t type); | |
| 428 const zend_class_entry *field_type_class(const upb_fielddef *field TSRMLS_DC); | |
| 429 | 219 |
| 430 // ----------------------------------------------------------------------------- | 220 // ----------------------------------------------------------------------------- |
| 431 // Utilities. | 221 // Utilities. |
| 432 // ----------------------------------------------------------------------------- | 222 // ----------------------------------------------------------------------------- |
| 433 | 223 |
| 434 // PHP <-> C conversion. | 224 // PHP Array utils. |
| 435 #define UNBOX(class_name, val) \ | 225 #define Z_ARRVAL_SIZE_P(zval_p) zend_hash_num_elements(Z_ARRVAL_P(zval_p)) |
| 436 (class_name*)zend_object_store_get_object(val TSRMLS_CC); | 226 #define Z_ARRVAL_BEGIN_P(zval_p) Z_ARRVAL_P(zval_p)->pListHead |
| 227 #define Z_BUCKET_NEXT_PP(bucket_pp) *bucket_pp = (*bucket_pp)->pListNext |
| 437 | 228 |
| 438 #define BOX(class_name, wrapper, intern, free_func) \ | 229 #define DEFINE_PHP_OBJECT(class_name, class_name_lower, name) \ |
| 439 MAKE_STD_ZVAL(wrapper); \ | 230 do { \ |
| 440 Z_TYPE_P(wrapper) = IS_OBJECT; \ | 231 zval* name; \ |
| 441 Z_OBJVAL_P(wrapper) \ | 232 MAKE_STD_ZVAL(name); \ |
| 442 .handle = \ | 233 object_init_ex(name, class_name_lower##_type); \ |
| 443 zend_objects_store_put(intern, NULL, free_func, NULL TSRMLS_CC); \ | 234 } while (0) |
| 444 Z_OBJVAL_P(wrapper).handlers = zend_get_std_object_handlers(); | 235 |
| 236 #define DEFINE_PHP_WRAPPER(class_name, class_name_lower, name, intern) \ |
| 237 zval* name; \ |
| 238 MAKE_STD_ZVAL(name); \ |
| 239 object_init_ex(name, class_name_lower##_type); \ |
| 240 Z_OBJVAL_P(name) \ |
| 241 .handle = zend_objects_store_put( \ |
| 242 intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \ |
| 243 class_name_lower##_free, NULL TSRMLS_CC); |
| 244 |
| 245 #define DEFINE_PHP_ZVAL(name) \ |
| 246 do { \ |
| 247 zval* name; \ |
| 248 MAKE_STD_ZVAL(name); \ |
| 249 } while (0) |
| 250 |
| 251 #define DEFINE_PHP_STRING(name, value) \ |
| 252 do { \ |
| 253 zval* name; \ |
| 254 MAKE_STD_ZVAL(name); \ |
| 255 ZVAL_STRING(name, value, 1); \ |
| 256 } while (0) |
| 257 |
| 258 // Upb Utilities |
| 259 |
| 260 void check_upb_status(const upb_status* status, const char* msg); |
| 261 |
| 262 #define CHECK_UPB(code, msg) \ |
| 263 do { \ |
| 264 upb_status status = UPB_STATUS_INIT; \ |
| 265 code; \ |
| 266 check_upb_status(&status, msg); \ |
| 267 } while (0) |
| 445 | 268 |
| 446 // Memory management | 269 // Memory management |
| 270 |
| 447 #define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name)) | 271 #define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name)) |
| 448 #define PEMALLOC(class_name) (class_name*) pemalloc(sizeof(class_name), 1) | |
| 449 #define ALLOC_N(class_name, n) (class_name*) emalloc(sizeof(class_name) * n) | 272 #define ALLOC_N(class_name, n) (class_name*) emalloc(sizeof(class_name) * n) |
| 450 #define FREE(object) efree(object) | 273 #define FREE(object) efree(object) |
| 451 #define PEFREE(object) pefree(object, 1) | |
| 452 | 274 |
| 453 // Create PHP internal instance. | 275 // Type Checking |
| 454 #define CREATE(class_name, intern, init_func) \ | 276 #define CHECK_TYPE(field, type) \ |
| 455 intern = ALLOC(class_name); \ | 277 if (Z_TYPE_P(field) != type) { \ |
| 456 memset(intern, 0, sizeof(class_name)); \ | 278 zend_error(E_ERROR, "Unexpected type"); \ |
| 457 init_func(intern TSRMLS_CC); | 279 } |
| 458 | |
| 459 // String argument. | |
| 460 #define STR(str) (str), strlen(str) | |
| 461 | |
| 462 // Zend Value | |
| 463 #define Z_OBJ_P(zval_p) \ | |
| 464 ((zend_object*)(EG(objects_store) \ | |
| 465 .object_buckets[Z_OBJ_HANDLE_P(zval_p)] \ | |
| 466 .bucket.obj.object)) | |
| 467 | 280 |
| 468 #endif // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ | 281 #endif // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ |
| OLD | NEW |