message.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2014 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. #include "message.h"
  31. #include <inttypes.h>
  32. #include <php.h>
  33. #include <stdlib.h>
  34. // This is not self-contained: it must be after other Zend includes.
  35. #include <Zend/zend_exceptions.h>
  36. #include "arena.h"
  37. #include "array.h"
  38. #include "convert.h"
  39. #include "def.h"
  40. #include "map.h"
  41. #include "php-upb.h"
  42. #include "protobuf.h"
  43. // -----------------------------------------------------------------------------
  44. // Message
  45. // -----------------------------------------------------------------------------
  46. typedef struct {
  47. zend_object std;
  48. zval arena;
  49. const Descriptor* desc;
  50. upb_msg *msg;
  51. } Message;
  52. zend_class_entry *message_ce;
  53. static zend_object_handlers message_object_handlers;
  54. // PHP Object Handlers /////////////////////////////////////////////////////////
  55. /**
  56. * Message_create()
  57. *
  58. * PHP class entry function to allocate and initialize a new Message object.
  59. */
  60. static zend_object* Message_create(zend_class_entry *class_type) {
  61. Message *intern = emalloc(sizeof(Message));
  62. // XXX(haberman): verify whether we actually want to take this route.
  63. class_type->default_properties_count = 0;
  64. zend_object_std_init(&intern->std, class_type);
  65. intern->std.handlers = &message_object_handlers;
  66. Arena_Init(&intern->arena);
  67. return &intern->std;
  68. }
  69. /**
  70. * Message_dtor()
  71. *
  72. * Object handler to destroy a Message. This releases all resources associated
  73. * with the message. Note that it is possible to access a destroyed object from
  74. * PHP in rare cases.
  75. */
  76. static void Message_dtor(zend_object* obj) {
  77. Message* intern = (Message*)obj;
  78. ObjCache_Delete(intern->msg);
  79. zval_dtor(&intern->arena);
  80. zend_object_std_dtor(&intern->std);
  81. }
  82. /**
  83. * get_field()
  84. *
  85. * Helper function to look up a field given a member name (as a string).
  86. */
  87. static const upb_fielddef *get_field(Message *msg, zval *member) {
  88. const upb_msgdef *m = msg->desc->msgdef;
  89. const upb_fielddef *f =
  90. upb_msgdef_ntof(m, Z_STRVAL_P(member), Z_STRLEN_P(member));
  91. if (!f) {
  92. zend_throw_exception_ex(NULL, 0, "No such property %s.",
  93. ZSTR_VAL(msg->desc->class_entry->name));
  94. }
  95. return f;
  96. }
  97. /**
  98. * Message_read_property()
  99. *
  100. * Object handler for reading a property in PHP. Called when PHP code does:
  101. *
  102. * $x = $message->foobar;
  103. *
  104. * Note that all properties of generated messages are private, so this should
  105. * only be possible to invoke from generated code, which has accessors like:
  106. *
  107. * public function getOptionalInt32()
  108. * {
  109. * return $this->optional_int32;
  110. * }
  111. *
  112. * We lookup the field and return the scalar, RepeatedField, or MapField for
  113. * this field.
  114. */
  115. static zval *Message_read_property(zval *obj, zval *member, int type,
  116. void **cache_slot, zval *rv) {
  117. Message* intern = (Message*)Z_OBJ_P(obj);
  118. const upb_fielddef *f = get_field(intern, member);
  119. upb_arena *arena = Arena_Get(&intern->arena);
  120. if (!f) return NULL;
  121. if (upb_fielddef_ismap(f)) {
  122. upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena);
  123. MapField_GetPhpWrapper(rv, msgval.map, f, &intern->arena);
  124. } else if (upb_fielddef_isseq(f)) {
  125. upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena);
  126. RepeatedField_GetPhpWrapper(rv, msgval.array, f, &intern->arena);
  127. } else {
  128. upb_msgval msgval = upb_msg_get(intern->msg, f);
  129. const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
  130. Convert_UpbToPhp(msgval, rv, upb_fielddef_type(f), subdesc, &intern->arena);
  131. }
  132. return rv;
  133. }
  134. /**
  135. * Message_write_property()
  136. *
  137. * Object handler for writing a property in PHP. Called when PHP code does:
  138. *
  139. * $message->foobar = $x;
  140. *
  141. * Note that all properties of generated messages are private, so this should
  142. * only be possible to invoke from generated code, which has accessors like:
  143. *
  144. * public function setOptionalInt32($var)
  145. * {
  146. * GPBUtil::checkInt32($var);
  147. * $this->optional_int32 = $var;
  148. *
  149. * return $this;
  150. * }
  151. *
  152. * The C extension version of checkInt32() doesn't actually check anything, so
  153. * we perform all checking and conversion in this function.
  154. */
  155. static void Message_write_property(zval *obj, zval *member, zval *val,
  156. void **cache_slot) {
  157. Message* intern = (Message*)Z_OBJ_P(obj);
  158. const upb_fielddef *f = get_field(intern, member);
  159. upb_arena *arena = Arena_Get(&intern->arena);
  160. upb_msgval msgval;
  161. if (!f) return;
  162. if (upb_fielddef_ismap(f)) {
  163. msgval.map_val = MapField_GetUpbMap(val, f, arena);
  164. if (!msgval.map_val) return;
  165. } else if (upb_fielddef_isseq(f)) {
  166. msgval.array_val = RepeatedField_GetUpbArray(val, f, arena);
  167. if (!msgval.array_val) return;
  168. } else {
  169. upb_fieldtype_t type = upb_fielddef_type(f);
  170. const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
  171. bool ok = Convert_PhpToUpb(val, &msgval, type, subdesc, arena);
  172. if (!ok) return;
  173. }
  174. upb_msg_set(intern->msg, f, msgval, arena);
  175. }
  176. /**
  177. * Message_get_property_ptr_ptr()
  178. *
  179. * Object handler for the get_property_ptr_ptr event in PHP. This returns a
  180. * reference to our internal properties. We don't support this, so we return
  181. * NULL.
  182. */
  183. static zval *Message_get_property_ptr_ptr(zval *object, zval *member, int type,
  184. void **cache_slot) {
  185. return NULL; // We do not have a properties table.
  186. }
  187. /**
  188. * Message_get_properties()
  189. *
  190. * Object handler for the get_properties event in PHP. This returns a HashTable
  191. * of our internal properties. We don't support this, so we return NULL.
  192. */
  193. static HashTable* Message_get_properties(zval* object TSRMLS_DC) {
  194. return NULL; // We don't offer direct references to our properties.
  195. }
  196. // C Functions from message.h. /////////////////////////////////////////////////
  197. // These are documented in the header file.
  198. void Message_GetPhpWrapper(zval *val, const Descriptor *desc, upb_msg *msg,
  199. zval *arena) {
  200. if (!msg) {
  201. ZVAL_NULL(val);
  202. return;
  203. }
  204. if (!ObjCache_Get(msg, val)) {
  205. Message *intern = emalloc(sizeof(Message));
  206. // XXX(haberman): verify whether we actually want to take this route.
  207. desc->class_entry->default_properties_count = 0;
  208. zend_object_std_init(&intern->std, desc->class_entry);
  209. intern->std.handlers = &message_object_handlers;
  210. ZVAL_COPY(&intern->arena, arena);
  211. intern->desc = desc;
  212. intern->msg = msg;
  213. ZVAL_OBJ(val, &intern->std);
  214. ObjCache_Add(intern->msg, &intern->std);
  215. }
  216. }
  217. bool Message_GetUpbMessage(zval *val, const Descriptor *desc, upb_arena *arena,
  218. upb_msg **msg) {
  219. PBPHP_ASSERT(desc);
  220. if (Z_ISREF_P(val)) {
  221. ZVAL_DEREF(val);
  222. }
  223. if (Z_TYPE_P(val) == IS_NULL) {
  224. *msg = NULL;
  225. return true;
  226. }
  227. if (Z_TYPE_P(val) == IS_OBJECT &&
  228. instanceof_function(Z_OBJCE_P(val), desc->class_entry)) {
  229. Message *intern = (Message*)Z_OBJ_P(val);
  230. upb_arena_fuse(arena, Arena_Get(&intern->arena));
  231. *msg = intern->msg;
  232. return true;
  233. } else {
  234. zend_throw_exception_ex(NULL, 0, "Given value is not an instance of %s.",
  235. ZSTR_VAL(desc->class_entry->name));
  236. return false;
  237. }
  238. }
  239. // Message PHP methods /////////////////////////////////////////////////////////
  240. /**
  241. * Message_InitFromPhp()
  242. *
  243. * Helper method to handle the initialization of a message from a PHP value, eg.
  244. *
  245. * $m = new TestMessage([
  246. * 'optional_int32' => -42,
  247. * 'optional_bool' => true,
  248. * 'optional_string' => 'a',
  249. * 'optional_enum' => TestEnum::ONE,
  250. * 'optional_message' => new Sub([
  251. * 'a' => 33
  252. * ]),
  253. * 'repeated_int32' => [-42, -52],
  254. * 'repeated_enum' => [TestEnum::ZERO, TestEnum::ONE],
  255. * 'repeated_message' => [new Sub(['a' => 34]),
  256. * new Sub(['a' => 35])],
  257. * 'map_int32_int32' => [-62 => -62],
  258. * 'map_int32_enum' => [1 => TestEnum::ONE],
  259. * 'map_int32_message' => [1 => new Sub(['a' => 36])],
  260. * ]);
  261. *
  262. * The initializer must be an array.
  263. */
  264. bool Message_InitFromPhp(upb_msg *msg, const upb_msgdef *m, zval *init,
  265. upb_arena *arena) {
  266. HashTable* table = HASH_OF(init);
  267. HashPosition pos;
  268. if (Z_ISREF_P(init)) {
  269. ZVAL_DEREF(init);
  270. }
  271. if (Z_TYPE_P(init) != IS_ARRAY) {
  272. zend_throw_exception_ex(NULL, 0,
  273. "Initializer for a message %s must be an array.",
  274. upb_msgdef_fullname(m));
  275. return false;
  276. }
  277. zend_hash_internal_pointer_reset_ex(table, &pos);
  278. while (true) { // Iterate over key/value pairs.
  279. zval key;
  280. zval *val;
  281. const upb_fielddef *f;
  282. upb_msgval msgval;
  283. zend_hash_get_current_key_zval_ex(table, &key, &pos);
  284. val = zend_hash_get_current_data_ex(table, &pos);
  285. if (!val) return true; // Finished iteration.
  286. if (Z_ISREF_P(val)) {
  287. ZVAL_DEREF(val);
  288. }
  289. f = upb_msgdef_ntof(m, Z_STRVAL_P(&key), Z_STRLEN_P(&key));
  290. if (!f) {
  291. zend_throw_exception_ex(NULL, 0,
  292. "No such field %s", Z_STRVAL_P(&key));
  293. return false;
  294. }
  295. if (upb_fielddef_ismap(f)) {
  296. msgval.map_val = MapField_GetUpbMap(val, f, arena);
  297. if (!msgval.map_val) return false;
  298. } else if (upb_fielddef_isseq(f)) {
  299. msgval.array_val = RepeatedField_GetUpbArray(val, f, arena);
  300. if (!msgval.array_val) return false;
  301. } else {
  302. const Descriptor *desc = Descriptor_GetFromFieldDef(f);
  303. upb_fieldtype_t type = upb_fielddef_type(f);
  304. if (!Convert_PhpToUpbAutoWrap(val, &msgval, type, desc, arena)) {
  305. return false;
  306. }
  307. }
  308. upb_msg_set(msg, f, msgval, arena);
  309. zend_hash_move_forward_ex(table, &pos);
  310. zval_dtor(&key);
  311. }
  312. }
  313. /**
  314. * Message::__construct()
  315. *
  316. * Constructor for Message.
  317. * @param array Map of initial values ['k' = val]
  318. */
  319. PHP_METHOD(Message, __construct) {
  320. Message* intern = (Message*)Z_OBJ_P(getThis());
  321. const Descriptor* desc = Descriptor_GetFromClassEntry(Z_OBJCE_P(getThis()));
  322. const upb_msgdef *msgdef = desc->msgdef;
  323. upb_arena *arena = Arena_Get(&intern->arena);
  324. zval *init_arr = NULL;
  325. intern->desc = desc;
  326. intern->msg = upb_msg_new(msgdef, arena);
  327. ObjCache_Add(intern->msg, &intern->std);
  328. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &init_arr) == FAILURE) {
  329. return;
  330. }
  331. if (init_arr) {
  332. Message_InitFromPhp(intern->msg, desc->msgdef, init_arr, arena);
  333. }
  334. }
  335. /**
  336. * Message::discardUnknownFields()
  337. *
  338. * Discards any unknown fields for this message or any submessages.
  339. */
  340. PHP_METHOD(Message, discardUnknownFields) {
  341. Message* intern = (Message*)Z_OBJ_P(getThis());
  342. upb_msg_discardunknown(intern->msg, intern->desc->msgdef, 64);
  343. }
  344. /**
  345. * Message::clear()
  346. *
  347. * Clears all fields of this message.
  348. */
  349. PHP_METHOD(Message, clear) {
  350. Message* intern = (Message*)Z_OBJ_P(getThis());
  351. upb_msg_clear(intern->msg, intern->desc->msgdef);
  352. }
  353. /**
  354. * Message::mergeFrom()
  355. *
  356. * Merges from the given message, which must be of the same class as us.
  357. * @param object Message to merge from.
  358. */
  359. PHP_METHOD(Message, mergeFrom) {
  360. Message* intern = (Message*)Z_OBJ_P(getThis());
  361. Message* from;
  362. upb_arena *arena = Arena_Get(&intern->arena);
  363. const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef);
  364. zval* value;
  365. char *pb;
  366. size_t size;
  367. bool ok;
  368. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &value,
  369. intern->desc->class_entry) == FAILURE) {
  370. return;
  371. }
  372. from = (Message*)Z_OBJ_P(value);
  373. // Should be guaranteed since we passed the class type to
  374. // zend_parse_parameters().
  375. PBPHP_ASSERT(from->desc == intern->desc);
  376. // TODO(haberman): use a temp arena for this once we can make upb_decode()
  377. // copy strings.
  378. pb = upb_encode(from->msg, l, arena, &size);
  379. if (!pb) {
  380. zend_throw_exception_ex(NULL, 0, "Max nesting exceeded");
  381. return;
  382. }
  383. ok = upb_decode(pb, size, intern->msg, l, arena);
  384. PBPHP_ASSERT(ok);
  385. }
  386. /**
  387. * Message::mergeFromString()
  388. *
  389. * Merges from the given string.
  390. * @param string Binary protobuf data to merge.
  391. */
  392. PHP_METHOD(Message, mergeFromString) {
  393. Message* intern = (Message*)Z_OBJ_P(getThis());
  394. char *data = NULL;
  395. char *data_copy = NULL;
  396. zend_long data_len;
  397. const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef);
  398. upb_arena *arena = Arena_Get(&intern->arena);
  399. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data, &data_len) ==
  400. FAILURE) {
  401. return;
  402. }
  403. // TODO(haberman): avoid this copy when we can make the decoder copy.
  404. data_copy = upb_arena_malloc(arena, data_len);
  405. memcpy(data_copy, data, data_len);
  406. if (!upb_decode(data_copy, data_len, intern->msg, l, arena)) {
  407. zend_throw_exception_ex(NULL, 0, "Error occurred during parsing");
  408. return;
  409. }
  410. }
  411. /**
  412. * Message::serializeToString()
  413. *
  414. * Serializes this message instance to protobuf data.
  415. * @return string Serialized protobuf data.
  416. */
  417. PHP_METHOD(Message, serializeToString) {
  418. Message* intern = (Message*)Z_OBJ_P(getThis());
  419. const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef);
  420. upb_arena *tmp_arena = upb_arena_new();
  421. char *data;
  422. size_t size;
  423. data = upb_encode(intern->msg, l, tmp_arena, &size);
  424. if (!data) {
  425. zend_throw_exception_ex(NULL, 0, "Error occurred during serialization");
  426. upb_arena_free(tmp_arena);
  427. return;
  428. }
  429. RETVAL_STRINGL(data, size);
  430. upb_arena_free(tmp_arena);
  431. }
  432. /**
  433. * Message::mergeFromJsonString()
  434. *
  435. * Merges the JSON data parsed from the given string.
  436. * @param string Serialized JSON data.
  437. */
  438. PHP_METHOD(Message, mergeFromJsonString) {
  439. Message* intern = (Message*)Z_OBJ_P(getThis());
  440. char *data = NULL;
  441. char *data_copy = NULL;
  442. zend_long data_len;
  443. upb_arena *arena = Arena_Get(&intern->arena);
  444. upb_status status;
  445. zend_bool ignore_json_unknown = false;
  446. int options = 0;
  447. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &data, &data_len,
  448. &ignore_json_unknown) == FAILURE) {
  449. return;
  450. }
  451. // TODO(haberman): avoid this copy when we can make the decoder copy.
  452. data_copy = upb_arena_malloc(arena, data_len + 1);
  453. memcpy(data_copy, data, data_len);
  454. data_copy[data_len] = '\0';
  455. if (ignore_json_unknown) {
  456. options |= UPB_JSONDEC_IGNOREUNKNOWN;
  457. }
  458. upb_status_clear(&status);
  459. if (!upb_json_decode(data_copy, data_len, intern->msg, intern->desc->msgdef,
  460. DescriptorPool_GetSymbolTable(), options, arena,
  461. &status)) {
  462. zend_throw_exception_ex(NULL, 0, "Error occurred during parsing: %s",
  463. upb_status_errmsg(&status));
  464. return;
  465. }
  466. }
  467. /**
  468. * Message::serializeToJsonString()
  469. *
  470. * Serializes this object to JSON.
  471. * @return string Serialized JSON data.
  472. */
  473. PHP_METHOD(Message, serializeToJsonString) {
  474. Message* intern = (Message*)Z_OBJ_P(getThis());
  475. size_t size;
  476. int options = 0;
  477. char buf[1024];
  478. zend_bool preserve_proto_fieldnames = false;
  479. upb_status status;
  480. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b",
  481. &preserve_proto_fieldnames) == FAILURE) {
  482. return;
  483. }
  484. if (preserve_proto_fieldnames) {
  485. options |= UPB_JSONENC_PROTONAMES;
  486. }
  487. upb_status_clear(&status);
  488. size = upb_json_encode(intern->msg, intern->desc->msgdef,
  489. DescriptorPool_GetSymbolTable(), options, buf,
  490. sizeof(buf), &status);
  491. if (!upb_ok(&status)) {
  492. zend_throw_exception_ex(NULL, 0,
  493. "Error occurred during JSON serialization: %s",
  494. upb_status_errmsg(&status));
  495. return;
  496. }
  497. if (size >= sizeof(buf)) {
  498. char *buf2 = malloc(size + 1);
  499. upb_json_encode(intern->msg, intern->desc->msgdef,
  500. DescriptorPool_GetSymbolTable(), options, buf2, size + 1,
  501. &status);
  502. RETVAL_STRINGL(buf2, size);
  503. free(buf2);
  504. } else {
  505. RETVAL_STRINGL(buf, size);
  506. }
  507. }
  508. /**
  509. * Message::readWrapperValue()
  510. *
  511. * Returns an unboxed value for the given field. This is called from generated
  512. * methods for wrapper fields, eg.
  513. *
  514. * public function getDoubleValueUnwrapped()
  515. * {
  516. * return $this->readWrapperValue("double_value");
  517. * }
  518. *
  519. * @return Unwrapped field value or null.
  520. */
  521. PHP_METHOD(Message, readWrapperValue) {
  522. Message* intern = (Message*)Z_OBJ_P(getThis());
  523. char* member;
  524. const upb_fielddef *f;
  525. zend_long size;
  526. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &member, &size) == FAILURE) {
  527. return;
  528. }
  529. f = upb_msgdef_ntof(intern->desc->msgdef, member, size);
  530. if (!f || !upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f))) {
  531. zend_throw_exception_ex(NULL, 0, "Message %s has no field %s",
  532. upb_msgdef_fullname(intern->desc->msgdef), member);
  533. return;
  534. }
  535. if (upb_msg_has(intern->msg, f)) {
  536. const upb_msg *wrapper = upb_msg_get(intern->msg, f).msg_val;
  537. const upb_msgdef *m = upb_fielddef_msgsubdef(f);
  538. const upb_fielddef *val_f = upb_msgdef_itof(m, 1);
  539. const upb_fieldtype_t val_type = upb_fielddef_type(val_f);
  540. upb_msgval msgval = upb_msg_get(wrapper, val_f);
  541. zval ret;
  542. Convert_UpbToPhp(msgval, &ret, val_type, NULL, &intern->arena);
  543. RETURN_ZVAL(&ret, 1, 0);
  544. } else {
  545. RETURN_NULL();
  546. }
  547. }
  548. /**
  549. * Message::writeWrapperValue()
  550. *
  551. * Sets the given wrapper field to the given unboxed value. This is called from
  552. * generated methods for wrapper fields, eg.
  553. *
  554. *
  555. * public function setDoubleValueUnwrapped($var)
  556. * {
  557. * $this->writeWrapperValue("double_value", $var);
  558. * return $this;
  559. * }
  560. *
  561. * @param Unwrapped field value or null.
  562. */
  563. PHP_METHOD(Message, writeWrapperValue) {
  564. Message* intern = (Message*)Z_OBJ_P(getThis());
  565. upb_arena *arena = Arena_Get(&intern->arena);
  566. char* member;
  567. const upb_fielddef *f;
  568. upb_msgval msgval;
  569. zend_long size;
  570. zval* val;
  571. if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &member, &size, &val) ==
  572. FAILURE) {
  573. return;
  574. }
  575. f = upb_msgdef_ntof(intern->desc->msgdef, member, size);
  576. if (!f || !upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f))) {
  577. zend_throw_exception_ex(NULL, 0, "Message %s has no field %s",
  578. upb_msgdef_fullname(intern->desc->msgdef), member);
  579. return;
  580. }
  581. if (Z_ISREF_P(val)) {
  582. ZVAL_DEREF(val);
  583. }
  584. if (Z_TYPE_P(val) == IS_NULL) {
  585. upb_msg_clearfield(intern->msg, f);
  586. } else {
  587. const upb_msgdef *m = upb_fielddef_msgsubdef(f);
  588. const upb_fielddef *val_f = upb_msgdef_itof(m, 1);
  589. upb_fieldtype_t val_type = upb_fielddef_type(val_f);
  590. upb_msg *wrapper;
  591. if (!Convert_PhpToUpb(val, &msgval, val_type, NULL, arena)) {
  592. return; // Error is already set.
  593. }
  594. wrapper = upb_msg_mutable(intern->msg, f, arena).msg;
  595. upb_msg_set(wrapper, val_f, msgval, arena);
  596. }
  597. }
  598. /**
  599. * Message::whichOneof()
  600. *
  601. * Given a oneof name, returns the name of the field that is set for this oneof,
  602. * or otherwise the empty string.
  603. *
  604. * @return string The field name in this oneof that is currently set.
  605. */
  606. PHP_METHOD(Message, whichOneof) {
  607. Message* intern = (Message*)Z_OBJ_P(getThis());
  608. const upb_oneofdef* oneof;
  609. const upb_fielddef* field;
  610. char* name;
  611. zend_long len;
  612. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &len) == FAILURE) {
  613. return;
  614. }
  615. oneof = upb_msgdef_ntoo(intern->desc->msgdef, name, len);
  616. if (!oneof) {
  617. zend_throw_exception_ex(NULL, 0, "Message %s has no oneof %s",
  618. upb_msgdef_fullname(intern->desc->msgdef), name);
  619. return;
  620. }
  621. field = upb_msg_whichoneof(intern->msg, oneof);
  622. RETURN_STRING(field ? upb_fielddef_name(field) : "");
  623. }
  624. /**
  625. * Message::readOneof()
  626. *
  627. * Returns the contents of the given oneof field, given a field number. Called
  628. * from generated code methods such as:
  629. *
  630. * public function getDoubleValueOneof()
  631. * {
  632. * return $this->readOneof(10);
  633. * }
  634. *
  635. * @return object The oneof's field value.
  636. */
  637. PHP_METHOD(Message, readOneof) {
  638. Message* intern = (Message*)Z_OBJ_P(getThis());
  639. zend_long field_num;
  640. const upb_fielddef* f;
  641. zval ret;
  642. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &field_num) == FAILURE) {
  643. return;
  644. }
  645. f = upb_msgdef_itof(intern->desc->msgdef, field_num);
  646. if (!f || !upb_fielddef_realcontainingoneof(f)) {
  647. php_error_docref(NULL, E_USER_ERROR,
  648. "Internal error, no such oneof field %d\n",
  649. (int)field_num);
  650. }
  651. {
  652. upb_msgval msgval = upb_msg_get(intern->msg, f);
  653. const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
  654. Convert_UpbToPhp(msgval, &ret, upb_fielddef_type(f), subdesc,
  655. &intern->arena);
  656. }
  657. RETURN_ZVAL(&ret, 1, 0);
  658. }
  659. /**
  660. * Message::writeOneof()
  661. *
  662. * Sets the contents of the given oneof field, given a field number. Called
  663. * from generated code methods such as:
  664. *
  665. * public function setDoubleValueOneof($var)
  666. * {
  667. * GPBUtil::checkMessage($var, \Google\Protobuf\DoubleValue::class);
  668. * $this->writeOneof(10, $var);
  669. *
  670. * return $this;
  671. * }
  672. *
  673. * The C extension version of GPBUtil::check*() does nothing, so we perform
  674. * all type checking and conversion here.
  675. *
  676. * @param integer The field number we are setting.
  677. * @param object The field value we want to set.
  678. */
  679. PHP_METHOD(Message, writeOneof) {
  680. Message* intern = (Message*)Z_OBJ_P(getThis());
  681. zend_long field_num;
  682. const upb_fielddef* f;
  683. upb_arena *arena = Arena_Get(&intern->arena);
  684. upb_msgval msgval;
  685. zval* val;
  686. if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &field_num, &val) ==
  687. FAILURE) {
  688. return;
  689. }
  690. f = upb_msgdef_itof(intern->desc->msgdef, field_num);
  691. if (!Convert_PhpToUpb(val, &msgval, upb_fielddef_type(f),
  692. Descriptor_GetFromFieldDef(f), arena)) {
  693. return;
  694. }
  695. upb_msg_set(intern->msg, f, msgval, arena);
  696. }
  697. static zend_function_entry Message_methods[] = {
  698. PHP_ME(Message, clear, NULL, ZEND_ACC_PUBLIC)
  699. PHP_ME(Message, discardUnknownFields, NULL, ZEND_ACC_PUBLIC)
  700. PHP_ME(Message, serializeToString, NULL, ZEND_ACC_PUBLIC)
  701. PHP_ME(Message, mergeFromString, NULL, ZEND_ACC_PUBLIC)
  702. PHP_ME(Message, serializeToJsonString, NULL, ZEND_ACC_PUBLIC)
  703. PHP_ME(Message, mergeFromJsonString, NULL, ZEND_ACC_PUBLIC)
  704. PHP_ME(Message, mergeFrom, NULL, ZEND_ACC_PUBLIC)
  705. PHP_ME(Message, readWrapperValue, NULL, ZEND_ACC_PROTECTED)
  706. PHP_ME(Message, writeWrapperValue, NULL, ZEND_ACC_PROTECTED)
  707. PHP_ME(Message, readOneof, NULL, ZEND_ACC_PROTECTED)
  708. PHP_ME(Message, writeOneof, NULL, ZEND_ACC_PROTECTED)
  709. PHP_ME(Message, whichOneof, NULL, ZEND_ACC_PROTECTED)
  710. PHP_ME(Message, __construct, NULL, ZEND_ACC_PROTECTED)
  711. ZEND_FE_END
  712. };
  713. /**
  714. * Message_ModuleInit()
  715. *
  716. * Called when the C extension is loaded to register all types.
  717. */
  718. void Message_ModuleInit() {
  719. zend_class_entry tmp_ce;
  720. zend_object_handlers *h = &message_object_handlers;
  721. INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\Message",
  722. Message_methods);
  723. message_ce = zend_register_internal_class(&tmp_ce);
  724. message_ce->create_object = Message_create;
  725. memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
  726. h->dtor_obj = Message_dtor;
  727. h->read_property = Message_read_property;
  728. h->write_property = Message_write_property;
  729. h->get_properties = Message_get_properties;
  730. h->get_property_ptr_ptr = Message_get_property_ptr_ptr;
  731. }