message.c 31 KB

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