| 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 |
| 1 #ifndef __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ | 31 #ifndef __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ |
| 2 #define __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ | 32 #define __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ |
| 3 | 33 |
| 4 #include <php.h> | 34 #include <php.h> |
| 5 | 35 |
| 36 // ubp.h has to be placed after php.h. Othwise, php.h will introduce NDEBUG. |
| 6 #include "upb.h" | 37 #include "upb.h" |
| 7 | 38 |
| 8 #define PHP_PROTOBUF_EXTNAME "protobuf" | 39 #define PHP_PROTOBUF_EXTNAME "protobuf" |
| 9 #define PHP_PROTOBUF_VERSION "0.01" | 40 #define PHP_PROTOBUF_VERSION "3.1.0a1" |
| 10 | 41 |
| 11 // Forward decls. | 42 #define MAX_LENGTH_OF_INT64 20 |
| 43 #define SIZEOF_INT64 8 |
| 44 |
| 45 // ----------------------------------------------------------------------------- |
| 46 // Forward Declaration |
| 47 // ---------------------------------------------------------------------------- |
| 48 |
| 12 struct DescriptorPool; | 49 struct DescriptorPool; |
| 13 struct Descriptor; | 50 struct Descriptor; |
| 51 struct EnumDescriptor; |
| 14 struct FieldDescriptor; | 52 struct FieldDescriptor; |
| 15 struct EnumDescriptor; | |
| 16 struct MessageLayout; | |
| 17 struct MessageField; | 53 struct MessageField; |
| 18 struct MessageHeader; | 54 struct MessageHeader; |
| 19 struct MessageBuilderContext; | 55 struct MessageLayout; |
| 20 struct EnumBuilderContext; | 56 struct RepeatedField; |
| 57 struct RepeatedFieldIter; |
| 58 struct MapField; |
| 21 | 59 |
| 22 typedef struct DescriptorPool DescriptorPool; | 60 typedef struct DescriptorPool DescriptorPool; |
| 23 typedef struct Descriptor Descriptor; | 61 typedef struct Descriptor Descriptor; |
| 62 typedef struct EnumDescriptor EnumDescriptor; |
| 24 typedef struct FieldDescriptor FieldDescriptor; | 63 typedef struct FieldDescriptor FieldDescriptor; |
| 25 typedef struct OneofDescriptor OneofDescriptor; | |
| 26 typedef struct EnumDescriptor EnumDescriptor; | |
| 27 typedef struct MessageLayout MessageLayout; | |
| 28 typedef struct MessageField MessageField; | 64 typedef struct MessageField MessageField; |
| 29 typedef struct MessageHeader MessageHeader; | 65 typedef struct MessageHeader MessageHeader; |
| 30 typedef struct MessageBuilderContext MessageBuilderContext; | 66 typedef struct MessageLayout MessageLayout; |
| 31 typedef struct OneofBuilderContext OneofBuilderContext; | 67 typedef struct RepeatedField RepeatedField; |
| 32 typedef struct EnumBuilderContext EnumBuilderContext; | 68 typedef struct RepeatedFieldIter RepeatedFieldIter; |
| 69 typedef struct MapField MapField; |
| 33 | 70 |
| 34 extern zend_class_entry* builder_type; | 71 // ----------------------------------------------------------------------------- |
| 35 extern zend_class_entry* descriptor_type; | 72 // Globals. |
| 36 extern zend_class_entry* message_builder_context_type; | 73 // ----------------------------------------------------------------------------- |
| 37 | |
| 38 extern DescriptorPool* generated_pool; // The actual generated pool | |
| 39 | 74 |
| 40 ZEND_BEGIN_MODULE_GLOBALS(protobuf) | 75 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) | 76 ZEND_END_MODULE_GLOBALS(protobuf) |
| 45 | 77 |
| 46 ZEND_DECLARE_MODULE_GLOBALS(protobuf) | 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); |
| 47 | 88 |
| 48 #ifdef ZTS | 89 // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor |
| 49 #define PROTOBUF_G(v) TSRMG(protobuf_globals_id, zend_protobuf_globals*, v) | 90 // instances. |
| 50 #else | 91 void add_def_obj(const void* def, zval* value); |
| 51 #define PROTOBUF_G(v) (protobuf_globals.v) | 92 zval* get_def_obj(const void* def); |
| 52 #endif | 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; |
| 53 | 101 |
| 54 // ----------------------------------------------------------------------------- | 102 // ----------------------------------------------------------------------------- |
| 55 // PHP functions and global variables. | 103 // Descriptor. |
| 56 // ----------------------------------------------------------------------------- | |
| 57 | |
| 58 PHP_MINIT_FUNCTION(protobuf); | |
| 59 | |
| 60 // ----------------------------------------------------------------------------- | |
| 61 // PHP class structure. | |
| 62 // ----------------------------------------------------------------------------- | 104 // ----------------------------------------------------------------------------- |
| 63 | 105 |
| 64 struct DescriptorPool { | 106 struct DescriptorPool { |
| 65 zend_object std; | 107 zend_object std; |
| 66 upb_symtab* symtab; | 108 upb_symtab* symtab; |
| 67 HashTable* pending_list; | 109 HashTable* pending_list; |
| 68 }; | 110 }; |
| 69 | 111 |
| 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 |
| 70 struct Descriptor { | 118 struct Descriptor { |
| 71 zend_object std; | 119 zend_object std; |
| 72 const upb_msgdef* msgdef; | 120 const upb_msgdef* msgdef; |
| 73 MessageLayout* layout; | 121 MessageLayout* layout; |
| 74 // zval* klass; // begins as NULL | 122 zend_class_entry* klass; // begins as NULL |
| 75 // const upb_handlers* fill_handlers; | 123 const upb_handlers* fill_handlers; |
| 76 // const upb_pbdecodermethod* fill_method; | 124 const upb_pbdecodermethod* fill_method; |
| 77 const upb_handlers* pb_serialize_handlers; | 125 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; | |
| 83 }; | 126 }; |
| 84 | 127 |
| 128 extern zend_class_entry* descriptor_type; |
| 129 |
| 130 void descriptor_name_set(Descriptor *desc, const char *name); |
| 131 |
| 85 struct FieldDescriptor { | 132 struct FieldDescriptor { |
| 86 zend_object std; | 133 zend_object std; |
| 87 const upb_fielddef* fielddef; | 134 const upb_fielddef* fielddef; |
| 88 }; | 135 }; |
| 89 | 136 |
| 90 struct OneofDescriptor { | |
| 91 zend_object std; | |
| 92 const upb_oneofdef* oneofdef; | |
| 93 }; | |
| 94 | |
| 95 struct EnumDescriptor { | 137 struct EnumDescriptor { |
| 96 zend_object std; | 138 zend_object std; |
| 97 const upb_enumdef* enumdef; | 139 const upb_enumdef* enumdef; |
| 98 // zval* module; // begins as NULL | 140 zend_class_entry* klass; // begins as NULL |
| 141 // VALUE module; // begins as nil |
| 99 }; | 142 }; |
| 100 | 143 |
| 144 extern zend_class_entry* enum_descriptor_type; |
| 145 |
| 101 // ----------------------------------------------------------------------------- | 146 // ----------------------------------------------------------------------------- |
| 102 // Native slot storage abstraction. | 147 // Message class creation. |
| 103 // ----------------------------------------------------------------------------- | 148 // ----------------------------------------------------------------------------- |
| 104 | 149 |
| 105 #define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t) | 150 void* message_data(void* msg); |
| 106 | 151 |
| 107 size_t native_slot_size(upb_fieldtype_t type); | 152 // Build PHP class for given descriptor. Instead of building from scratch, this |
| 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); |
| 108 | 156 |
| 109 #define MAP_KEY_FIELD 1 | 157 extern zend_object_handlers* message_handlers; |
| 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); | |
| 126 | 158 |
| 127 // ----------------------------------------------------------------------------- | 159 // ----------------------------------------------------------------------------- |
| 128 // Message layout / storage. | 160 // Message layout / storage. |
| 129 // ----------------------------------------------------------------------------- | 161 // ----------------------------------------------------------------------------- |
| 130 | 162 |
| 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 |
| 131 #define MESSAGE_FIELD_NO_CASE ((size_t)-1) | 211 #define MESSAGE_FIELD_NO_CASE ((size_t)-1) |
| 132 | 212 |
| 133 struct MessageField { | 213 struct MessageField { |
| 134 size_t offset; | 214 size_t offset; |
| 135 size_t case_offset; // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE. | 215 int cache_index; // Each field except oneof field has a zval cache to avoid |
| 216 // multiple creation when being accessed. |
| 217 size_t case_offset; // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE. |
| 136 }; | 218 }; |
| 137 | 219 |
| 138 struct MessageLayout { | 220 struct MessageLayout { |
| 139 const upb_msgdef* msgdef; | 221 const upb_msgdef* msgdef; |
| 140 MessageField* fields; | 222 MessageField* fields; |
| 141 size_t size; | 223 size_t size; |
| 142 }; | 224 }; |
| 143 | 225 |
| 144 void layout_init(MessageLayout* layout, void* storage); | 226 struct MessageHeader { |
| 227 zend_object std; // Stores properties table and class info of PHP instance. |
| 228 // This is needed for MessageHeader to be accessed via PHP. |
| 229 Descriptor* descriptor; // Kept alive by self.class.descriptor reference. |
| 230 // The real message data is appended after MessageHeader. |
| 231 }; |
| 232 |
| 233 MessageLayout* create_layout(const upb_msgdef* msgdef); |
| 234 void layout_init(MessageLayout* layout, void* storage, |
| 235 zval** properties_table TSRMLS_DC); |
| 145 zval* layout_get(MessageLayout* layout, const void* storage, | 236 zval* layout_get(MessageLayout* layout, const void* storage, |
| 146 const upb_fielddef* field TSRMLS_DC); | 237 const upb_fielddef* field, zval** cache TSRMLS_DC); |
| 147 MessageLayout* create_layout(const upb_msgdef* msgdef); | 238 void layout_set(MessageLayout* layout, MessageHeader* header, |
| 239 const upb_fielddef* field, zval* val TSRMLS_DC); |
| 148 void free_layout(MessageLayout* layout); | 240 void free_layout(MessageLayout* layout); |
| 149 zval* native_slot_get(upb_fieldtype_t type, /*VALUE type_class,*/ | 241 |
| 150 const void* memory TSRMLS_DC); | 242 PHP_METHOD(Message, readOneof); |
| 151 | 243 PHP_METHOD(Message, writeOneof); |
| 152 // ----------------------------------------------------------------------------- | 244 PHP_METHOD(Message, __construct); |
| 153 // Message class creation. | 245 |
| 154 // ----------------------------------------------------------------------------- | 246 // ----------------------------------------------------------------------------- |
| 155 | 247 // Encode / Decode. |
| 156 struct MessageHeader { | 248 // ----------------------------------------------------------------------------- |
| 157 zend_object std; | 249 |
| 158 Descriptor* descriptor; // kept alive by self.class.descriptor reference. | 250 // Maximum depth allowed during encoding, to avoid stack overflows due to |
| 159 // Data comes after this. | 251 // cycles. |
| 160 }; | 252 #define ENCODE_MAX_NESTING 63 |
| 161 | 253 |
| 162 struct MessageBuilderContext { | 254 // Constructs the upb decoder method for parsing messages of this type. |
| 163 zend_object std; | 255 // This is called from the message class creation code. |
| 164 zval* descriptor; | 256 const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor *desc, |
| 165 zval* pool; | 257 const void *owner); |
| 166 }; | |
| 167 | |
| 168 struct OneofBuilderContext { | |
| 169 zend_object std; | |
| 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 | 258 |
| 206 PHP_METHOD(Message, encode); | 259 PHP_METHOD(Message, encode); |
| 207 const zend_class_entry* build_class_from_descriptor( | 260 PHP_METHOD(Message, decode); |
| 208 zval* php_descriptor TSRMLS_DC); | 261 |
| 209 | 262 // ----------------------------------------------------------------------------- |
| 210 PHP_FUNCTION(get_generated_pool); | 263 // Type check / conversion. |
| 211 | 264 // ----------------------------------------------------------------------------- |
| 212 // ----------------------------------------------------------------------------- | 265 |
| 213 // Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor | 266 bool protobuf_convert_to_int32(zval* from, int32_t* to); |
| 214 // instances. | 267 bool protobuf_convert_to_uint32(zval* from, uint32_t* to); |
| 215 // ---------------------------------------------------------------------------- | 268 bool protobuf_convert_to_int64(zval* from, int64_t* to); |
| 216 | 269 bool protobuf_convert_to_uint64(zval* from, uint64_t* to); |
| 217 void add_def_obj(const void* def, zval* value); | 270 bool protobuf_convert_to_float(zval* from, float* to); |
| 218 zval* get_def_obj(const void* def); | 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); |
| 219 | 429 |
| 220 // ----------------------------------------------------------------------------- | 430 // ----------------------------------------------------------------------------- |
| 221 // Utilities. | 431 // Utilities. |
| 222 // ----------------------------------------------------------------------------- | 432 // ----------------------------------------------------------------------------- |
| 223 | 433 |
| 224 // PHP Array utils. | 434 // PHP <-> C conversion. |
| 225 #define Z_ARRVAL_SIZE_P(zval_p) zend_hash_num_elements(Z_ARRVAL_P(zval_p)) | 435 #define UNBOX(class_name, val) \ |
| 226 #define Z_ARRVAL_BEGIN_P(zval_p) Z_ARRVAL_P(zval_p)->pListHead | 436 (class_name*)zend_object_store_get_object(val TSRMLS_CC); |
| 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) | |
| 268 | 445 |
| 269 // Memory management | 446 // Memory management |
| 270 | |
| 271 #define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name)) | 447 #define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name)) |
| 448 #define PEMALLOC(class_name) (class_name*) pemalloc(sizeof(class_name), 1) |
| 272 #define ALLOC_N(class_name, n) (class_name*) emalloc(sizeof(class_name) * n) | 449 #define ALLOC_N(class_name, n) (class_name*) emalloc(sizeof(class_name) * n) |
| 273 #define FREE(object) efree(object) | 450 #define FREE(object) efree(object) |
| 274 | 451 #define PEFREE(object) pefree(object, 1) |
| 275 // Type Checking | 452 |
| 276 #define CHECK_TYPE(field, type) \ | 453 // Create PHP internal instance. |
| 277 if (Z_TYPE_P(field) != type) { \ | 454 #define CREATE(class_name, intern, init_func) \ |
| 278 zend_error(E_ERROR, "Unexpected type"); \ | 455 intern = ALLOC(class_name); \ |
| 279 } | 456 memset(intern, 0, sizeof(class_name)); \ |
| 457 init_func(intern TSRMLS_CC); |
| 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)) |
| 280 | 467 |
| 281 #endif // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ | 468 #endif // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ |
| OLD | NEW |