message.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  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, PROTO_STR *member) {
  88. const upb_msgdef *m = msg->desc->msgdef;
  89. const upb_fielddef *f =
  90. upb_msgdef_ntof(m, PROTO_STRVAL_P(member), PROTO_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. static bool MessageEq(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m);
  98. /**
  99. * ValueEq()()
  100. */
  101. bool ValueEq(upb_msgval val1, upb_msgval val2, upb_fieldtype_t type,
  102. const upb_msgdef *m) {
  103. switch (type) {
  104. case UPB_TYPE_BOOL:
  105. return val1.bool_val == val2.bool_val;
  106. case UPB_TYPE_INT32:
  107. case UPB_TYPE_UINT32:
  108. case UPB_TYPE_ENUM:
  109. return val1.int32_val == val2.int32_val;
  110. case UPB_TYPE_INT64:
  111. case UPB_TYPE_UINT64:
  112. return val1.int64_val == val2.int64_val;
  113. case UPB_TYPE_FLOAT:
  114. return val1.float_val == val2.float_val;
  115. case UPB_TYPE_DOUBLE:
  116. return val1.double_val == val2.double_val;
  117. case UPB_TYPE_STRING:
  118. case UPB_TYPE_BYTES:
  119. return val1.str_val.size == val2.str_val.size &&
  120. memcmp(val1.str_val.data, val2.str_val.data, val1.str_val.size) == 0;
  121. case UPB_TYPE_MESSAGE:
  122. return MessageEq(val1.msg_val, val2.msg_val, m);
  123. default:
  124. return false;
  125. }
  126. }
  127. /**
  128. * MessageEq()
  129. */
  130. static bool MessageEq(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m) {
  131. upb_msg_field_iter i;
  132. for(upb_msg_field_begin(&i, m);
  133. !upb_msg_field_done(&i);
  134. upb_msg_field_next(&i)) {
  135. const upb_fielddef *f = upb_msg_iter_field(&i);
  136. upb_msgval val1 = upb_msg_get(m1, f);
  137. upb_msgval val2 = upb_msg_get(m2, f);
  138. upb_fieldtype_t type = upb_fielddef_type(f);
  139. const upb_msgdef *sub_m = upb_fielddef_msgsubdef(f);
  140. if (upb_fielddef_haspresence(f)) {
  141. if (upb_msg_has(m1, f) != upb_msg_has(m2, f)) {
  142. return false;
  143. }
  144. if (!upb_msg_has(m1, f)) continue;
  145. }
  146. if (upb_fielddef_ismap(f)) {
  147. const upb_fielddef *key_f = upb_msgdef_itof(sub_m, 1);
  148. const upb_fielddef *val_f = upb_msgdef_itof(sub_m, 2);
  149. upb_fieldtype_t key_type = upb_fielddef_type(key_f);
  150. upb_fieldtype_t val_type = upb_fielddef_type(val_f);
  151. const upb_msgdef *val_m = upb_fielddef_msgsubdef(val_f);
  152. if (!MapEq(val1.map_val, val2.map_val, key_type, val_type, val_m)) {
  153. return false;
  154. }
  155. } else if (upb_fielddef_isseq(f)) {
  156. if (!ArrayEq(val1.array_val, val2.array_val, type, sub_m)) return false;
  157. } else {
  158. if (!ValueEq(val1, val2, type, sub_m)) return false;
  159. }
  160. }
  161. return true;
  162. }
  163. /**
  164. * Message_compare_objects()
  165. *
  166. * Object handler for comparing two message objects. Called whenever PHP code
  167. * does:
  168. *
  169. * $m1 == $m2
  170. */
  171. static int Message_compare_objects(zval *m1, zval *m2) {
  172. Message* intern1 = (Message*)Z_OBJ_P(m1);
  173. Message* intern2 = (Message*)Z_OBJ_P(m2);
  174. const upb_msgdef *m = intern1->desc->msgdef;
  175. if (intern2->desc->msgdef != m) return 1;
  176. return MessageEq(intern1->msg, intern2->msg, m) ? 0 : 1;
  177. }
  178. /**
  179. * Message_has_property()
  180. *
  181. * Object handler for testing whether a property exists. Called when PHP code
  182. * does any of:
  183. *
  184. * isset($message->foobar);
  185. * property_exists($message->foobar);
  186. *
  187. * Note that all properties of generated messages are private, so this should
  188. * only be possible to invoke from generated code, which has accessors like this
  189. * (if the field has presence):
  190. *
  191. * public function hasOptionalInt32()
  192. * {
  193. * return isset($this->optional_int32);
  194. * }
  195. */
  196. static int Message_has_property(PROTO_VAL *obj, PROTO_STR *member,
  197. int has_set_exists,
  198. void **cache_slot) {
  199. Message* intern = PROTO_MSG_P(obj);
  200. const upb_fielddef *f = get_field(intern, member);
  201. if (!f) return 0;
  202. if (!upb_fielddef_haspresence(f)) {
  203. zend_throw_exception_ex(
  204. NULL, 0,
  205. "Cannot call isset() on field %s which does not have presence.",
  206. ZSTR_VAL(intern->desc->class_entry->name));
  207. return 0;
  208. }
  209. return upb_msg_has(intern->msg, f);
  210. }
  211. /**
  212. * Message_unset_property()
  213. *
  214. * Object handler for unsetting a property. Called when PHP code calls:
  215. * does any of:
  216. *
  217. * unset($message->foobar);
  218. *
  219. * Note that all properties of generated messages are private, so this should
  220. * only be possible to invoke from generated code, which has accessors like this
  221. * (if the field has presence):
  222. *
  223. * public function clearOptionalInt32()
  224. * {
  225. * unset($this->optional_int32);
  226. * }
  227. */
  228. static void Message_unset_property(PROTO_VAL *obj, PROTO_STR *member,
  229. void **cache_slot) {
  230. Message* intern = PROTO_MSG_P(obj);
  231. const upb_fielddef *f = get_field(intern, member);
  232. if (!f) return;
  233. if (!upb_fielddef_haspresence(f)) {
  234. zend_throw_exception_ex(
  235. NULL, 0,
  236. "Cannot call unset() on field %s which does not have presence.",
  237. ZSTR_VAL(intern->desc->class_entry->name));
  238. return;
  239. }
  240. upb_msg_clearfield(intern->msg, f);
  241. }
  242. /**
  243. * Message_read_property()
  244. *
  245. * Object handler for reading a property in PHP. Called when PHP code does:
  246. *
  247. * $x = $message->foobar;
  248. *
  249. * Note that all properties of generated messages are private, so this should
  250. * only be possible to invoke from generated code, which has accessors like:
  251. *
  252. * public function getOptionalInt32()
  253. * {
  254. * return $this->optional_int32;
  255. * }
  256. *
  257. * We lookup the field and return the scalar, RepeatedField, or MapField for
  258. * this field.
  259. */
  260. static zval *Message_read_property(PROTO_VAL *obj, PROTO_STR *member,
  261. int type, void **cache_slot, zval *rv) {
  262. Message* intern = PROTO_MSG_P(obj);
  263. const upb_fielddef *f = get_field(intern, member);
  264. upb_arena *arena = Arena_Get(&intern->arena);
  265. if (!f) return NULL;
  266. if (upb_fielddef_ismap(f)) {
  267. upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena);
  268. MapField_GetPhpWrapper(rv, msgval.map, f, &intern->arena);
  269. } else if (upb_fielddef_isseq(f)) {
  270. upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena);
  271. RepeatedField_GetPhpWrapper(rv, msgval.array, f, &intern->arena);
  272. } else {
  273. upb_msgval msgval = upb_msg_get(intern->msg, f);
  274. const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
  275. Convert_UpbToPhp(msgval, rv, upb_fielddef_type(f), subdesc, &intern->arena);
  276. }
  277. return rv;
  278. }
  279. /**
  280. * Message_write_property()
  281. *
  282. * Object handler for writing a property in PHP. Called when PHP code does:
  283. *
  284. * $message->foobar = $x;
  285. *
  286. * Note that all properties of generated messages are private, so this should
  287. * only be possible to invoke from generated code, which has accessors like:
  288. *
  289. * public function setOptionalInt32($var)
  290. * {
  291. * GPBUtil::checkInt32($var);
  292. * $this->optional_int32 = $var;
  293. *
  294. * return $this;
  295. * }
  296. *
  297. * The C extension version of checkInt32() doesn't actually check anything, so
  298. * we perform all checking and conversion in this function.
  299. */
  300. static PROTO_RETURN_VAL Message_write_property(
  301. PROTO_VAL *obj, PROTO_STR *member, zval *val, void **cache_slot) {
  302. Message* intern = PROTO_MSG_P(obj);
  303. const upb_fielddef *f = get_field(intern, member);
  304. upb_arena *arena = Arena_Get(&intern->arena);
  305. upb_msgval msgval;
  306. if (!f) goto error;
  307. if (upb_fielddef_ismap(f)) {
  308. msgval.map_val = MapField_GetUpbMap(val, f, arena);
  309. if (!msgval.map_val) goto error;
  310. } else if (upb_fielddef_isseq(f)) {
  311. msgval.array_val = RepeatedField_GetUpbArray(val, f, arena);
  312. if (!msgval.array_val) goto error;
  313. } else {
  314. upb_fieldtype_t type = upb_fielddef_type(f);
  315. const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
  316. bool ok = Convert_PhpToUpb(val, &msgval, type, subdesc, arena);
  317. if (!ok) goto error;
  318. }
  319. upb_msg_set(intern->msg, f, msgval, arena);
  320. #if PHP_VERSION_ID < 70400
  321. return;
  322. #else
  323. return val;
  324. #endif
  325. error:
  326. #if PHP_VERSION_ID < 70400
  327. return;
  328. #else
  329. return &EG(error_zval);
  330. #endif
  331. }
  332. /**
  333. * Message_get_property_ptr_ptr()
  334. *
  335. * Object handler for the get_property_ptr_ptr event in PHP. This returns a
  336. * reference to our internal properties. We don't support this, so we return
  337. * NULL.
  338. */
  339. static zval *Message_get_property_ptr_ptr(PROTO_VAL *object, PROTO_STR *member,
  340. int type,
  341. void **cache_slot) {
  342. return NULL; // We do not have a properties table.
  343. }
  344. /**
  345. * Message_get_properties()
  346. *
  347. * Object handler for the get_properties event in PHP. This returns a HashTable
  348. * of our internal properties. We don't support this, so we return NULL.
  349. */
  350. static HashTable *Message_get_properties(PROTO_VAL *object) {
  351. return NULL; // We don't offer direct references to our properties.
  352. }
  353. // C Functions from message.h. /////////////////////////////////////////////////
  354. // These are documented in the header file.
  355. void Message_GetPhpWrapper(zval *val, const Descriptor *desc, upb_msg *msg,
  356. zval *arena) {
  357. if (!msg) {
  358. ZVAL_NULL(val);
  359. return;
  360. }
  361. if (!ObjCache_Get(msg, val)) {
  362. Message *intern = emalloc(sizeof(Message));
  363. // XXX(haberman): verify whether we actually want to take this route.
  364. desc->class_entry->default_properties_count = 0;
  365. zend_object_std_init(&intern->std, desc->class_entry);
  366. intern->std.handlers = &message_object_handlers;
  367. ZVAL_COPY(&intern->arena, arena);
  368. intern->desc = desc;
  369. intern->msg = msg;
  370. ZVAL_OBJ(val, &intern->std);
  371. ObjCache_Add(intern->msg, &intern->std);
  372. }
  373. }
  374. bool Message_GetUpbMessage(zval *val, const Descriptor *desc, upb_arena *arena,
  375. upb_msg **msg) {
  376. PBPHP_ASSERT(desc);
  377. if (Z_ISREF_P(val)) {
  378. ZVAL_DEREF(val);
  379. }
  380. if (Z_TYPE_P(val) == IS_NULL) {
  381. *msg = NULL;
  382. return true;
  383. }
  384. if (Z_TYPE_P(val) == IS_OBJECT &&
  385. instanceof_function(Z_OBJCE_P(val), desc->class_entry)) {
  386. Message *intern = (Message*)Z_OBJ_P(val);
  387. upb_arena_fuse(arena, Arena_Get(&intern->arena));
  388. *msg = intern->msg;
  389. return true;
  390. } else {
  391. zend_throw_exception_ex(NULL, 0, "Given value is not an instance of %s.",
  392. ZSTR_VAL(desc->class_entry->name));
  393. return false;
  394. }
  395. }
  396. // Message PHP methods /////////////////////////////////////////////////////////
  397. /**
  398. * Message_InitFromPhp()
  399. *
  400. * Helper method to handle the initialization of a message from a PHP value, eg.
  401. *
  402. * $m = new TestMessage([
  403. * 'optional_int32' => -42,
  404. * 'optional_bool' => true,
  405. * 'optional_string' => 'a',
  406. * 'optional_enum' => TestEnum::ONE,
  407. * 'optional_message' => new Sub([
  408. * 'a' => 33
  409. * ]),
  410. * 'repeated_int32' => [-42, -52],
  411. * 'repeated_enum' => [TestEnum::ZERO, TestEnum::ONE],
  412. * 'repeated_message' => [new Sub(['a' => 34]),
  413. * new Sub(['a' => 35])],
  414. * 'map_int32_int32' => [-62 => -62],
  415. * 'map_int32_enum' => [1 => TestEnum::ONE],
  416. * 'map_int32_message' => [1 => new Sub(['a' => 36])],
  417. * ]);
  418. *
  419. * The initializer must be an array.
  420. */
  421. bool Message_InitFromPhp(upb_msg *msg, const upb_msgdef *m, zval *init,
  422. upb_arena *arena) {
  423. HashTable* table = HASH_OF(init);
  424. HashPosition pos;
  425. if (Z_ISREF_P(init)) {
  426. ZVAL_DEREF(init);
  427. }
  428. if (Z_TYPE_P(init) != IS_ARRAY) {
  429. zend_throw_exception_ex(NULL, 0,
  430. "Initializer for a message %s must be an array.",
  431. upb_msgdef_fullname(m));
  432. return false;
  433. }
  434. zend_hash_internal_pointer_reset_ex(table, &pos);
  435. while (true) { // Iterate over key/value pairs.
  436. zval key;
  437. zval *val;
  438. const upb_fielddef *f;
  439. upb_msgval msgval;
  440. zend_hash_get_current_key_zval_ex(table, &key, &pos);
  441. val = zend_hash_get_current_data_ex(table, &pos);
  442. if (!val) return true; // Finished iteration.
  443. if (Z_ISREF_P(val)) {
  444. ZVAL_DEREF(val);
  445. }
  446. f = upb_msgdef_ntof(m, Z_STRVAL_P(&key), Z_STRLEN_P(&key));
  447. if (!f) {
  448. zend_throw_exception_ex(NULL, 0,
  449. "No such field %s", Z_STRVAL_P(&key));
  450. return false;
  451. }
  452. if (upb_fielddef_ismap(f)) {
  453. msgval.map_val = MapField_GetUpbMap(val, f, arena);
  454. if (!msgval.map_val) return false;
  455. } else if (upb_fielddef_isseq(f)) {
  456. msgval.array_val = RepeatedField_GetUpbArray(val, f, arena);
  457. if (!msgval.array_val) return false;
  458. } else {
  459. const Descriptor *desc = Descriptor_GetFromFieldDef(f);
  460. upb_fieldtype_t type = upb_fielddef_type(f);
  461. if (!Convert_PhpToUpbAutoWrap(val, &msgval, type, desc, arena)) {
  462. return false;
  463. }
  464. }
  465. upb_msg_set(msg, f, msgval, arena);
  466. zend_hash_move_forward_ex(table, &pos);
  467. zval_dtor(&key);
  468. }
  469. }
  470. /**
  471. * Message::__construct()
  472. *
  473. * Constructor for Message.
  474. * @param array Map of initial values ['k' = val]
  475. */
  476. PHP_METHOD(Message, __construct) {
  477. Message* intern = (Message*)Z_OBJ_P(getThis());
  478. const Descriptor* desc = Descriptor_GetFromClassEntry(Z_OBJCE_P(getThis()));
  479. const upb_msgdef *msgdef = desc->msgdef;
  480. upb_arena *arena = Arena_Get(&intern->arena);
  481. zval *init_arr = NULL;
  482. intern->desc = desc;
  483. intern->msg = upb_msg_new(msgdef, arena);
  484. ObjCache_Add(intern->msg, &intern->std);
  485. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &init_arr) == FAILURE) {
  486. return;
  487. }
  488. if (init_arr) {
  489. Message_InitFromPhp(intern->msg, desc->msgdef, init_arr, arena);
  490. }
  491. }
  492. /**
  493. * Message::discardUnknownFields()
  494. *
  495. * Discards any unknown fields for this message or any submessages.
  496. */
  497. PHP_METHOD(Message, discardUnknownFields) {
  498. Message* intern = (Message*)Z_OBJ_P(getThis());
  499. upb_msg_discardunknown(intern->msg, intern->desc->msgdef, 64);
  500. }
  501. /**
  502. * Message::clear()
  503. *
  504. * Clears all fields of this message.
  505. */
  506. PHP_METHOD(Message, clear) {
  507. Message* intern = (Message*)Z_OBJ_P(getThis());
  508. upb_msg_clear(intern->msg, intern->desc->msgdef);
  509. }
  510. /**
  511. * Message::mergeFrom()
  512. *
  513. * Merges from the given message, which must be of the same class as us.
  514. * @param object Message to merge from.
  515. */
  516. PHP_METHOD(Message, mergeFrom) {
  517. Message* intern = (Message*)Z_OBJ_P(getThis());
  518. Message* from;
  519. upb_arena *arena = Arena_Get(&intern->arena);
  520. const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef);
  521. zval* value;
  522. char *pb;
  523. size_t size;
  524. bool ok;
  525. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &value,
  526. intern->desc->class_entry) == FAILURE) {
  527. return;
  528. }
  529. from = (Message*)Z_OBJ_P(value);
  530. // Should be guaranteed since we passed the class type to
  531. // zend_parse_parameters().
  532. PBPHP_ASSERT(from->desc == intern->desc);
  533. // TODO(haberman): use a temp arena for this once we can make upb_decode()
  534. // copy strings.
  535. pb = upb_encode(from->msg, l, arena, &size);
  536. if (!pb) {
  537. zend_throw_exception_ex(NULL, 0, "Max nesting exceeded");
  538. return;
  539. }
  540. ok = upb_decode(pb, size, intern->msg, l, arena);
  541. PBPHP_ASSERT(ok);
  542. }
  543. /**
  544. * Message::mergeFromString()
  545. *
  546. * Merges from the given string.
  547. * @param string Binary protobuf data to merge.
  548. */
  549. PHP_METHOD(Message, mergeFromString) {
  550. Message* intern = (Message*)Z_OBJ_P(getThis());
  551. char *data = NULL;
  552. char *data_copy = NULL;
  553. zend_long data_len;
  554. const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef);
  555. upb_arena *arena = Arena_Get(&intern->arena);
  556. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data, &data_len) ==
  557. FAILURE) {
  558. return;
  559. }
  560. // TODO(haberman): avoid this copy when we can make the decoder copy.
  561. data_copy = upb_arena_malloc(arena, data_len);
  562. memcpy(data_copy, data, data_len);
  563. if (!upb_decode(data_copy, data_len, intern->msg, l, arena)) {
  564. zend_throw_exception_ex(NULL, 0, "Error occurred during parsing");
  565. return;
  566. }
  567. }
  568. /**
  569. * Message::serializeToString()
  570. *
  571. * Serializes this message instance to protobuf data.
  572. * @return string Serialized protobuf data.
  573. */
  574. PHP_METHOD(Message, serializeToString) {
  575. Message* intern = (Message*)Z_OBJ_P(getThis());
  576. const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef);
  577. upb_arena *tmp_arena = upb_arena_new();
  578. char *data;
  579. size_t size;
  580. data = upb_encode(intern->msg, l, tmp_arena, &size);
  581. if (!data) {
  582. zend_throw_exception_ex(NULL, 0, "Error occurred during serialization");
  583. upb_arena_free(tmp_arena);
  584. return;
  585. }
  586. RETVAL_STRINGL(data, size);
  587. upb_arena_free(tmp_arena);
  588. }
  589. /**
  590. * Message::mergeFromJsonString()
  591. *
  592. * Merges the JSON data parsed from the given string.
  593. * @param string Serialized JSON data.
  594. */
  595. PHP_METHOD(Message, mergeFromJsonString) {
  596. Message* intern = (Message*)Z_OBJ_P(getThis());
  597. char *data = NULL;
  598. char *data_copy = NULL;
  599. zend_long data_len;
  600. upb_arena *arena = Arena_Get(&intern->arena);
  601. upb_status status;
  602. zend_bool ignore_json_unknown = false;
  603. int options = 0;
  604. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &data, &data_len,
  605. &ignore_json_unknown) == FAILURE) {
  606. return;
  607. }
  608. // TODO(haberman): avoid this copy when we can make the decoder copy.
  609. data_copy = upb_arena_malloc(arena, data_len + 1);
  610. memcpy(data_copy, data, data_len);
  611. data_copy[data_len] = '\0';
  612. if (ignore_json_unknown) {
  613. options |= UPB_JSONDEC_IGNOREUNKNOWN;
  614. }
  615. upb_status_clear(&status);
  616. if (!upb_json_decode(data_copy, data_len, intern->msg, intern->desc->msgdef,
  617. DescriptorPool_GetSymbolTable(), options, arena,
  618. &status)) {
  619. zend_throw_exception_ex(NULL, 0, "Error occurred during parsing: %s",
  620. upb_status_errmsg(&status));
  621. return;
  622. }
  623. }
  624. /**
  625. * Message::serializeToJsonString()
  626. *
  627. * Serializes this object to JSON.
  628. * @return string Serialized JSON data.
  629. */
  630. PHP_METHOD(Message, serializeToJsonString) {
  631. Message* intern = (Message*)Z_OBJ_P(getThis());
  632. size_t size;
  633. int options = 0;
  634. char buf[1024];
  635. zend_bool preserve_proto_fieldnames = false;
  636. upb_status status;
  637. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b",
  638. &preserve_proto_fieldnames) == FAILURE) {
  639. return;
  640. }
  641. if (preserve_proto_fieldnames) {
  642. options |= UPB_JSONENC_PROTONAMES;
  643. }
  644. upb_status_clear(&status);
  645. size = upb_json_encode(intern->msg, intern->desc->msgdef,
  646. DescriptorPool_GetSymbolTable(), options, buf,
  647. sizeof(buf), &status);
  648. if (!upb_ok(&status)) {
  649. zend_throw_exception_ex(NULL, 0,
  650. "Error occurred during JSON serialization: %s",
  651. upb_status_errmsg(&status));
  652. return;
  653. }
  654. if (size >= sizeof(buf)) {
  655. char *buf2 = malloc(size + 1);
  656. upb_json_encode(intern->msg, intern->desc->msgdef,
  657. DescriptorPool_GetSymbolTable(), options, buf2, size + 1,
  658. &status);
  659. RETVAL_STRINGL(buf2, size);
  660. free(buf2);
  661. } else {
  662. RETVAL_STRINGL(buf, size);
  663. }
  664. }
  665. /**
  666. * Message::readWrapperValue()
  667. *
  668. * Returns an unboxed value for the given field. This is called from generated
  669. * methods for wrapper fields, eg.
  670. *
  671. * public function getDoubleValueUnwrapped()
  672. * {
  673. * return $this->readWrapperValue("double_value");
  674. * }
  675. *
  676. * @return Unwrapped field value or null.
  677. */
  678. PHP_METHOD(Message, readWrapperValue) {
  679. Message* intern = (Message*)Z_OBJ_P(getThis());
  680. char* member;
  681. const upb_fielddef *f;
  682. zend_long size;
  683. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &member, &size) == FAILURE) {
  684. return;
  685. }
  686. f = upb_msgdef_ntof(intern->desc->msgdef, member, size);
  687. if (!f || !upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f))) {
  688. zend_throw_exception_ex(NULL, 0, "Message %s has no field %s",
  689. upb_msgdef_fullname(intern->desc->msgdef), member);
  690. return;
  691. }
  692. if (upb_msg_has(intern->msg, f)) {
  693. const upb_msg *wrapper = upb_msg_get(intern->msg, f).msg_val;
  694. const upb_msgdef *m = upb_fielddef_msgsubdef(f);
  695. const upb_fielddef *val_f = upb_msgdef_itof(m, 1);
  696. const upb_fieldtype_t val_type = upb_fielddef_type(val_f);
  697. upb_msgval msgval = upb_msg_get(wrapper, val_f);
  698. zval ret;
  699. Convert_UpbToPhp(msgval, &ret, val_type, NULL, &intern->arena);
  700. RETURN_ZVAL(&ret, 1, 0);
  701. } else {
  702. RETURN_NULL();
  703. }
  704. }
  705. /**
  706. * Message::writeWrapperValue()
  707. *
  708. * Sets the given wrapper field to the given unboxed value. This is called from
  709. * generated methods for wrapper fields, eg.
  710. *
  711. *
  712. * public function setDoubleValueUnwrapped($var)
  713. * {
  714. * $this->writeWrapperValue("double_value", $var);
  715. * return $this;
  716. * }
  717. *
  718. * @param Unwrapped field value or null.
  719. */
  720. PHP_METHOD(Message, writeWrapperValue) {
  721. Message* intern = (Message*)Z_OBJ_P(getThis());
  722. upb_arena *arena = Arena_Get(&intern->arena);
  723. char* member;
  724. const upb_fielddef *f;
  725. upb_msgval msgval;
  726. zend_long size;
  727. zval* val;
  728. if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &member, &size, &val) ==
  729. FAILURE) {
  730. return;
  731. }
  732. f = upb_msgdef_ntof(intern->desc->msgdef, member, size);
  733. if (!f || !upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f))) {
  734. zend_throw_exception_ex(NULL, 0, "Message %s has no field %s",
  735. upb_msgdef_fullname(intern->desc->msgdef), member);
  736. return;
  737. }
  738. if (Z_ISREF_P(val)) {
  739. ZVAL_DEREF(val);
  740. }
  741. if (Z_TYPE_P(val) == IS_NULL) {
  742. upb_msg_clearfield(intern->msg, f);
  743. } else {
  744. const upb_msgdef *m = upb_fielddef_msgsubdef(f);
  745. const upb_fielddef *val_f = upb_msgdef_itof(m, 1);
  746. upb_fieldtype_t val_type = upb_fielddef_type(val_f);
  747. upb_msg *wrapper;
  748. if (!Convert_PhpToUpb(val, &msgval, val_type, NULL, arena)) {
  749. return; // Error is already set.
  750. }
  751. wrapper = upb_msg_mutable(intern->msg, f, arena).msg;
  752. upb_msg_set(wrapper, val_f, msgval, arena);
  753. }
  754. }
  755. /**
  756. * Message::whichOneof()
  757. *
  758. * Given a oneof name, returns the name of the field that is set for this oneof,
  759. * or otherwise the empty string.
  760. *
  761. * @return string The field name in this oneof that is currently set.
  762. */
  763. PHP_METHOD(Message, whichOneof) {
  764. Message* intern = (Message*)Z_OBJ_P(getThis());
  765. const upb_oneofdef* oneof;
  766. const upb_fielddef* field;
  767. char* name;
  768. zend_long len;
  769. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &len) == FAILURE) {
  770. return;
  771. }
  772. oneof = upb_msgdef_ntoo(intern->desc->msgdef, name, len);
  773. if (!oneof) {
  774. zend_throw_exception_ex(NULL, 0, "Message %s has no oneof %s",
  775. upb_msgdef_fullname(intern->desc->msgdef), name);
  776. return;
  777. }
  778. field = upb_msg_whichoneof(intern->msg, oneof);
  779. RETURN_STRING(field ? upb_fielddef_name(field) : "");
  780. }
  781. /**
  782. * Message::readOneof()
  783. *
  784. * Returns the contents of the given oneof field, given a field number. Called
  785. * from generated code methods such as:
  786. *
  787. * public function getDoubleValueOneof()
  788. * {
  789. * return $this->readOneof(10);
  790. * }
  791. *
  792. * @return object The oneof's field value.
  793. */
  794. PHP_METHOD(Message, readOneof) {
  795. Message* intern = (Message*)Z_OBJ_P(getThis());
  796. zend_long field_num;
  797. const upb_fielddef* f;
  798. zval ret;
  799. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &field_num) == FAILURE) {
  800. return;
  801. }
  802. f = upb_msgdef_itof(intern->desc->msgdef, field_num);
  803. if (!f || !upb_fielddef_realcontainingoneof(f)) {
  804. php_error_docref(NULL, E_USER_ERROR,
  805. "Internal error, no such oneof field %d\n",
  806. (int)field_num);
  807. }
  808. {
  809. upb_msgval msgval = upb_msg_get(intern->msg, f);
  810. const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
  811. Convert_UpbToPhp(msgval, &ret, upb_fielddef_type(f), subdesc,
  812. &intern->arena);
  813. }
  814. RETURN_ZVAL(&ret, 1, 0);
  815. }
  816. /**
  817. * Message::writeOneof()
  818. *
  819. * Sets the contents of the given oneof field, given a field number. Called
  820. * from generated code methods such as:
  821. *
  822. * public function setDoubleValueOneof($var)
  823. * {
  824. * GPBUtil::checkMessage($var, \Google\Protobuf\DoubleValue::class);
  825. * $this->writeOneof(10, $var);
  826. *
  827. * return $this;
  828. * }
  829. *
  830. * The C extension version of GPBUtil::check*() does nothing, so we perform
  831. * all type checking and conversion here.
  832. *
  833. * @param integer The field number we are setting.
  834. * @param object The field value we want to set.
  835. */
  836. PHP_METHOD(Message, writeOneof) {
  837. Message* intern = (Message*)Z_OBJ_P(getThis());
  838. zend_long field_num;
  839. const upb_fielddef* f;
  840. upb_arena *arena = Arena_Get(&intern->arena);
  841. upb_msgval msgval;
  842. zval* val;
  843. if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &field_num, &val) ==
  844. FAILURE) {
  845. return;
  846. }
  847. f = upb_msgdef_itof(intern->desc->msgdef, field_num);
  848. if (!Convert_PhpToUpb(val, &msgval, upb_fielddef_type(f),
  849. Descriptor_GetFromFieldDef(f), arena)) {
  850. return;
  851. }
  852. upb_msg_set(intern->msg, f, msgval, arena);
  853. }
  854. ZEND_BEGIN_ARG_INFO_EX(arginfo_void, 0, 0, 0)
  855. ZEND_END_ARG_INFO()
  856. ZEND_BEGIN_ARG_INFO_EX(arginfo_mergeFrom, 0, 0, 1)
  857. ZEND_ARG_INFO(0, data)
  858. ZEND_END_ARG_INFO()
  859. ZEND_BEGIN_ARG_INFO_EX(arginfo_read, 0, 0, 1)
  860. ZEND_ARG_INFO(0, field)
  861. ZEND_END_ARG_INFO()
  862. ZEND_BEGIN_ARG_INFO_EX(arginfo_write, 0, 0, 2)
  863. ZEND_ARG_INFO(0, field)
  864. ZEND_ARG_INFO(0, value)
  865. ZEND_END_ARG_INFO()
  866. static zend_function_entry Message_methods[] = {
  867. PHP_ME(Message, clear, arginfo_void, ZEND_ACC_PUBLIC)
  868. PHP_ME(Message, discardUnknownFields, arginfo_void, ZEND_ACC_PUBLIC)
  869. PHP_ME(Message, serializeToString, arginfo_void, ZEND_ACC_PUBLIC)
  870. PHP_ME(Message, mergeFromString, arginfo_mergeFrom, ZEND_ACC_PUBLIC)
  871. PHP_ME(Message, serializeToJsonString, arginfo_void, ZEND_ACC_PUBLIC)
  872. PHP_ME(Message, mergeFromJsonString, arginfo_mergeFrom, ZEND_ACC_PUBLIC)
  873. PHP_ME(Message, mergeFrom, arginfo_mergeFrom, ZEND_ACC_PUBLIC)
  874. PHP_ME(Message, readWrapperValue, arginfo_read, ZEND_ACC_PROTECTED)
  875. PHP_ME(Message, writeWrapperValue, arginfo_write, ZEND_ACC_PROTECTED)
  876. PHP_ME(Message, readOneof, arginfo_read, ZEND_ACC_PROTECTED)
  877. PHP_ME(Message, writeOneof, arginfo_write, ZEND_ACC_PROTECTED)
  878. PHP_ME(Message, whichOneof, arginfo_read, ZEND_ACC_PROTECTED)
  879. PHP_ME(Message, __construct, arginfo_void, ZEND_ACC_PROTECTED)
  880. ZEND_FE_END
  881. };
  882. /**
  883. * Message_ModuleInit()
  884. *
  885. * Called when the C extension is loaded to register all types.
  886. */
  887. void Message_ModuleInit() {
  888. zend_class_entry tmp_ce;
  889. zend_object_handlers *h = &message_object_handlers;
  890. INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\Message",
  891. Message_methods);
  892. message_ce = zend_register_internal_class(&tmp_ce);
  893. message_ce->create_object = Message_create;
  894. memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
  895. h->dtor_obj = Message_dtor;
  896. h->compare_objects = Message_compare_objects;
  897. h->read_property = Message_read_property;
  898. h->write_property = Message_write_property;
  899. h->has_property = Message_has_property;
  900. h->unset_property = Message_unset_property;
  901. h->get_properties = Message_get_properties;
  902. h->get_property_ptr_ptr = Message_get_property_ptr_ptr;
  903. }