message.c 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378
  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 <Zend/zend_inheritance.h>
  37. #include "arena.h"
  38. #include "array.h"
  39. #include "convert.h"
  40. #include "def.h"
  41. #include "map.h"
  42. #include "php-upb.h"
  43. #include "protobuf.h"
  44. // -----------------------------------------------------------------------------
  45. // Message
  46. // -----------------------------------------------------------------------------
  47. typedef struct {
  48. zend_object std;
  49. zval arena;
  50. const Descriptor* desc;
  51. upb_msg *msg;
  52. } Message;
  53. zend_class_entry *message_ce;
  54. static zend_object_handlers message_object_handlers;
  55. static void Message_SuppressDefaultProperties(zend_class_entry *class_type) {
  56. // We suppress all default properties, because all our properties are handled
  57. // by our read_property handler.
  58. //
  59. // This also allows us to put our zend_object member at the beginning of our
  60. // struct -- instead of putting it at the end with pointer fixups to access
  61. // our own data, as recommended in the docs -- because Zend won't add any of
  62. // its own storage directly after the zend_object if default_properties_count
  63. // == 0.
  64. //
  65. // This is not officially supported, but since it simplifies the code, we'll
  66. // do it for as long as it works in practice.
  67. class_type->default_properties_count = 0;
  68. }
  69. // PHP Object Handlers /////////////////////////////////////////////////////////
  70. /**
  71. * Message_create()
  72. *
  73. * PHP class entry function to allocate and initialize a new Message object.
  74. */
  75. static zend_object* Message_create(zend_class_entry *class_type) {
  76. Message *intern = emalloc(sizeof(Message));
  77. Message_SuppressDefaultProperties(class_type);
  78. zend_object_std_init(&intern->std, class_type);
  79. intern->std.handlers = &message_object_handlers;
  80. Arena_Init(&intern->arena);
  81. return &intern->std;
  82. }
  83. /**
  84. * Message_dtor()
  85. *
  86. * Object handler to destroy a Message. This releases all resources associated
  87. * with the message. Note that it is possible to access a destroyed object from
  88. * PHP in rare cases.
  89. */
  90. static void Message_dtor(zend_object* obj) {
  91. Message* intern = (Message*)obj;
  92. ObjCache_Delete(intern->msg);
  93. zval_dtor(&intern->arena);
  94. zend_object_std_dtor(&intern->std);
  95. }
  96. /**
  97. * get_field()
  98. *
  99. * Helper function to look up a field given a member name (as a string).
  100. */
  101. static const upb_fielddef *get_field(Message *msg, PROTO_STR *member) {
  102. const upb_msgdef *m = msg->desc->msgdef;
  103. const upb_fielddef *f =
  104. upb_msgdef_ntof(m, PROTO_STRVAL_P(member), PROTO_STRLEN_P(member));
  105. if (!f) {
  106. zend_throw_exception_ex(NULL, 0, "No such property %s.",
  107. ZSTR_VAL(msg->desc->class_entry->name));
  108. }
  109. return f;
  110. }
  111. static void Message_get(Message *intern, const upb_fielddef *f, zval *rv) {
  112. upb_arena *arena = Arena_Get(&intern->arena);
  113. if (upb_fielddef_ismap(f)) {
  114. upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena);
  115. MapField_GetPhpWrapper(rv, msgval.map, MapType_Get(f), &intern->arena);
  116. } else if (upb_fielddef_isseq(f)) {
  117. upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena);
  118. RepeatedField_GetPhpWrapper(rv, msgval.array, TypeInfo_Get(f),
  119. &intern->arena);
  120. } else {
  121. upb_msgval msgval = upb_msg_get(intern->msg, f);
  122. Convert_UpbToPhp(msgval, rv, TypeInfo_Get(f), &intern->arena);
  123. }
  124. }
  125. static bool Message_set(Message *intern, const upb_fielddef *f, zval *val) {
  126. upb_arena *arena = Arena_Get(&intern->arena);
  127. upb_msgval msgval;
  128. if (upb_fielddef_ismap(f)) {
  129. msgval.map_val = MapField_GetUpbMap(val, MapType_Get(f), arena);
  130. if (!msgval.map_val) return false;
  131. } else if (upb_fielddef_isseq(f)) {
  132. msgval.array_val = RepeatedField_GetUpbArray(val, TypeInfo_Get(f), arena);
  133. if (!msgval.array_val) return false;
  134. } else {
  135. if (!Convert_PhpToUpb(val, &msgval, TypeInfo_Get(f), arena)) return false;
  136. }
  137. upb_msg_set(intern->msg, f, msgval, arena);
  138. return true;
  139. }
  140. static bool MessageEq(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m);
  141. /**
  142. * ValueEq()
  143. */
  144. bool ValueEq(upb_msgval val1, upb_msgval val2, TypeInfo type) {
  145. switch (type.type) {
  146. case UPB_TYPE_BOOL:
  147. return val1.bool_val == val2.bool_val;
  148. case UPB_TYPE_INT32:
  149. case UPB_TYPE_UINT32:
  150. case UPB_TYPE_ENUM:
  151. return val1.int32_val == val2.int32_val;
  152. case UPB_TYPE_INT64:
  153. case UPB_TYPE_UINT64:
  154. return val1.int64_val == val2.int64_val;
  155. case UPB_TYPE_FLOAT:
  156. return val1.float_val == val2.float_val;
  157. case UPB_TYPE_DOUBLE:
  158. return val1.double_val == val2.double_val;
  159. case UPB_TYPE_STRING:
  160. case UPB_TYPE_BYTES:
  161. return val1.str_val.size == val2.str_val.size &&
  162. memcmp(val1.str_val.data, val2.str_val.data, val1.str_val.size) == 0;
  163. case UPB_TYPE_MESSAGE:
  164. return MessageEq(val1.msg_val, val2.msg_val, type.desc->msgdef);
  165. default:
  166. return false;
  167. }
  168. }
  169. /**
  170. * MessageEq()
  171. */
  172. static bool MessageEq(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m) {
  173. upb_msg_field_iter i;
  174. for(upb_msg_field_begin(&i, m);
  175. !upb_msg_field_done(&i);
  176. upb_msg_field_next(&i)) {
  177. const upb_fielddef *f = upb_msg_iter_field(&i);
  178. upb_msgval val1 = upb_msg_get(m1, f);
  179. upb_msgval val2 = upb_msg_get(m2, f);
  180. if (upb_fielddef_haspresence(f)) {
  181. if (upb_msg_has(m1, f) != upb_msg_has(m2, f)) {
  182. return false;
  183. }
  184. if (!upb_msg_has(m1, f)) continue;
  185. }
  186. if (upb_fielddef_ismap(f)) {
  187. if (!MapEq(val1.map_val, val2.map_val, MapType_Get(f))) return false;
  188. } else if (upb_fielddef_isseq(f)) {
  189. if (!ArrayEq(val1.array_val, val2.array_val, TypeInfo_Get(f))) return false;
  190. } else {
  191. if (!ValueEq(val1, val2, TypeInfo_Get(f))) return false;
  192. }
  193. }
  194. return true;
  195. }
  196. /**
  197. * Message_compare_objects()
  198. *
  199. * Object handler for comparing two message objects. Called whenever PHP code
  200. * does:
  201. *
  202. * $m1 == $m2
  203. */
  204. static int Message_compare_objects(zval *m1, zval *m2) {
  205. Message* intern1 = (Message*)Z_OBJ_P(m1);
  206. Message* intern2 = (Message*)Z_OBJ_P(m2);
  207. const upb_msgdef *m = intern1->desc->msgdef;
  208. if (intern2->desc->msgdef != m) return 1;
  209. return MessageEq(intern1->msg, intern2->msg, m) ? 0 : 1;
  210. }
  211. /**
  212. * Message_has_property()
  213. *
  214. * Object handler for testing whether a property exists. Called when PHP code
  215. * does any of:
  216. *
  217. * isset($message->foobar);
  218. * property_exists($message->foobar);
  219. *
  220. * Note that all properties of generated messages are private, so this should
  221. * only be possible to invoke from generated code, which has accessors like this
  222. * (if the field has presence):
  223. *
  224. * public function hasOptionalInt32()
  225. * {
  226. * return isset($this->optional_int32);
  227. * }
  228. */
  229. static int Message_has_property(PROTO_VAL *obj, PROTO_STR *member,
  230. int has_set_exists,
  231. void **cache_slot) {
  232. Message* intern = PROTO_VAL_P(obj);
  233. const upb_fielddef *f = get_field(intern, member);
  234. if (!f) return 0;
  235. if (!upb_fielddef_haspresence(f)) {
  236. zend_throw_exception_ex(
  237. NULL, 0,
  238. "Cannot call isset() on field %s which does not have presence.",
  239. ZSTR_VAL(intern->desc->class_entry->name));
  240. return 0;
  241. }
  242. return upb_msg_has(intern->msg, f);
  243. }
  244. /**
  245. * Message_unset_property()
  246. *
  247. * Object handler for unsetting a property. Called when PHP code calls:
  248. * does any of:
  249. *
  250. * unset($message->foobar);
  251. *
  252. * Note that all properties of generated messages are private, so this should
  253. * only be possible to invoke from generated code, which has accessors like this
  254. * (if the field has presence):
  255. *
  256. * public function clearOptionalInt32()
  257. * {
  258. * unset($this->optional_int32);
  259. * }
  260. */
  261. static void Message_unset_property(PROTO_VAL *obj, PROTO_STR *member,
  262. void **cache_slot) {
  263. Message* intern = PROTO_VAL_P(obj);
  264. const upb_fielddef *f = get_field(intern, member);
  265. if (!f) return;
  266. if (!upb_fielddef_haspresence(f)) {
  267. zend_throw_exception_ex(
  268. NULL, 0,
  269. "Cannot call unset() on field %s which does not have presence.",
  270. ZSTR_VAL(intern->desc->class_entry->name));
  271. return;
  272. }
  273. upb_msg_clearfield(intern->msg, f);
  274. }
  275. /**
  276. * Message_read_property()
  277. *
  278. * Object handler for reading a property in PHP. Called when PHP code does:
  279. *
  280. * $x = $message->foobar;
  281. *
  282. * Note that all properties of generated messages are private, so this should
  283. * only be possible to invoke from generated code, which has accessors like:
  284. *
  285. * public function getOptionalInt32()
  286. * {
  287. * return $this->optional_int32;
  288. * }
  289. *
  290. * We lookup the field and return the scalar, RepeatedField, or MapField for
  291. * this field.
  292. */
  293. static zval *Message_read_property(PROTO_VAL *obj, PROTO_STR *member,
  294. int type, void **cache_slot, zval *rv) {
  295. Message* intern = PROTO_VAL_P(obj);
  296. const upb_fielddef *f = get_field(intern, member);
  297. if (!f) return &EG(uninitialized_zval);
  298. Message_get(intern, f, rv);
  299. return rv;
  300. }
  301. /**
  302. * Message_write_property()
  303. *
  304. * Object handler for writing a property in PHP. Called when PHP code does:
  305. *
  306. * $message->foobar = $x;
  307. *
  308. * Note that all properties of generated messages are private, so this should
  309. * only be possible to invoke from generated code, which has accessors like:
  310. *
  311. * public function setOptionalInt32($var)
  312. * {
  313. * GPBUtil::checkInt32($var);
  314. * $this->optional_int32 = $var;
  315. *
  316. * return $this;
  317. * }
  318. *
  319. * The C extension version of checkInt32() doesn't actually check anything, so
  320. * we perform all checking and conversion in this function.
  321. */
  322. static PROTO_RETURN_VAL Message_write_property(
  323. PROTO_VAL *obj, PROTO_STR *member, zval *val, void **cache_slot) {
  324. Message* intern = PROTO_VAL_P(obj);
  325. const upb_fielddef *f = get_field(intern, member);
  326. if (f && Message_set(intern, f, val)) {
  327. #if PHP_VERSION_ID < 70400
  328. return;
  329. #else
  330. return val;
  331. #endif
  332. } else {
  333. #if PHP_VERSION_ID < 70400
  334. return;
  335. #else
  336. return &EG(error_zval);
  337. #endif
  338. }
  339. }
  340. /**
  341. * Message_get_property_ptr_ptr()
  342. *
  343. * Object handler for the get_property_ptr_ptr event in PHP. This returns a
  344. * reference to our internal properties. We don't support this, so we return
  345. * NULL.
  346. */
  347. static zval *Message_get_property_ptr_ptr(PROTO_VAL *object, PROTO_STR *member,
  348. int type,
  349. void **cache_slot) {
  350. return NULL; // We do not have a properties table.
  351. }
  352. /**
  353. * Message_clone_obj()
  354. *
  355. * Object handler for cloning an object in PHP. Called when PHP code does:
  356. *
  357. * $msg2 = clone $msg;
  358. */
  359. static zend_object *Message_clone_obj(PROTO_VAL *object) {
  360. Message* intern = PROTO_VAL_P(object);
  361. upb_msg *clone = upb_msg_new(intern->desc->msgdef, Arena_Get(&intern->arena));
  362. // TODO: copy unknown fields?
  363. // TODO: use official upb msg copy function
  364. memcpy(clone, intern->msg, upb_msgdef_layout(intern->desc->msgdef)->size);
  365. zval ret;
  366. Message_GetPhpWrapper(&ret, intern->desc, clone, &intern->arena);
  367. return Z_OBJ_P(&ret);
  368. }
  369. /**
  370. * Message_get_properties()
  371. *
  372. * Object handler for the get_properties event in PHP. This returns a HashTable
  373. * of our internal properties. We don't support this, so we return NULL.
  374. */
  375. static HashTable *Message_get_properties(PROTO_VAL *object) {
  376. return NULL; // We don't offer direct references to our properties.
  377. }
  378. // C Functions from message.h. /////////////////////////////////////////////////
  379. // These are documented in the header file.
  380. void Message_GetPhpWrapper(zval *val, const Descriptor *desc, upb_msg *msg,
  381. zval *arena) {
  382. if (!msg) {
  383. ZVAL_NULL(val);
  384. return;
  385. }
  386. if (!ObjCache_Get(msg, val)) {
  387. Message *intern = emalloc(sizeof(Message));
  388. Message_SuppressDefaultProperties(desc->class_entry);
  389. zend_object_std_init(&intern->std, desc->class_entry);
  390. intern->std.handlers = &message_object_handlers;
  391. ZVAL_COPY(&intern->arena, arena);
  392. intern->desc = desc;
  393. intern->msg = msg;
  394. ZVAL_OBJ(val, &intern->std);
  395. ObjCache_Add(intern->msg, &intern->std);
  396. }
  397. }
  398. bool Message_GetUpbMessage(zval *val, const Descriptor *desc, upb_arena *arena,
  399. upb_msg **msg) {
  400. PBPHP_ASSERT(desc);
  401. if (Z_ISREF_P(val)) {
  402. ZVAL_DEREF(val);
  403. }
  404. if (Z_TYPE_P(val) == IS_NULL) {
  405. *msg = NULL;
  406. return true;
  407. }
  408. if (Z_TYPE_P(val) == IS_OBJECT &&
  409. instanceof_function(Z_OBJCE_P(val), desc->class_entry)) {
  410. Message *intern = (Message*)Z_OBJ_P(val);
  411. upb_arena_fuse(arena, Arena_Get(&intern->arena));
  412. *msg = intern->msg;
  413. return true;
  414. } else {
  415. zend_throw_exception_ex(NULL, 0, "Given value is not an instance of %s.",
  416. ZSTR_VAL(desc->class_entry->name));
  417. return false;
  418. }
  419. }
  420. // Message PHP methods /////////////////////////////////////////////////////////
  421. /**
  422. * Message_InitFromPhp()
  423. *
  424. * Helper method to handle the initialization of a message from a PHP value, eg.
  425. *
  426. * $m = new TestMessage([
  427. * 'optional_int32' => -42,
  428. * 'optional_bool' => true,
  429. * 'optional_string' => 'a',
  430. * 'optional_enum' => TestEnum::ONE,
  431. * 'optional_message' => new Sub([
  432. * 'a' => 33
  433. * ]),
  434. * 'repeated_int32' => [-42, -52],
  435. * 'repeated_enum' => [TestEnum::ZERO, TestEnum::ONE],
  436. * 'repeated_message' => [new Sub(['a' => 34]),
  437. * new Sub(['a' => 35])],
  438. * 'map_int32_int32' => [-62 => -62],
  439. * 'map_int32_enum' => [1 => TestEnum::ONE],
  440. * 'map_int32_message' => [1 => new Sub(['a' => 36])],
  441. * ]);
  442. *
  443. * The initializer must be an array.
  444. */
  445. bool Message_InitFromPhp(upb_msg *msg, const upb_msgdef *m, zval *init,
  446. upb_arena *arena) {
  447. HashTable* table = HASH_OF(init);
  448. HashPosition pos;
  449. if (Z_ISREF_P(init)) {
  450. ZVAL_DEREF(init);
  451. }
  452. if (Z_TYPE_P(init) != IS_ARRAY) {
  453. zend_throw_exception_ex(NULL, 0,
  454. "Initializer for a message %s must be an array.",
  455. upb_msgdef_fullname(m));
  456. return false;
  457. }
  458. zend_hash_internal_pointer_reset_ex(table, &pos);
  459. while (true) { // Iterate over key/value pairs.
  460. zval key;
  461. zval *val;
  462. const upb_fielddef *f;
  463. upb_msgval msgval;
  464. zend_hash_get_current_key_zval_ex(table, &key, &pos);
  465. val = zend_hash_get_current_data_ex(table, &pos);
  466. if (!val) return true; // Finished iteration.
  467. if (Z_ISREF_P(val)) {
  468. ZVAL_DEREF(val);
  469. }
  470. f = upb_msgdef_ntof(m, Z_STRVAL_P(&key), Z_STRLEN_P(&key));
  471. if (!f) {
  472. zend_throw_exception_ex(NULL, 0,
  473. "No such field %s", Z_STRVAL_P(&key));
  474. return false;
  475. }
  476. if (upb_fielddef_ismap(f)) {
  477. msgval.map_val = MapField_GetUpbMap(val, MapType_Get(f), arena);
  478. if (!msgval.map_val) return false;
  479. } else if (upb_fielddef_isseq(f)) {
  480. msgval.array_val = RepeatedField_GetUpbArray(val, TypeInfo_Get(f), arena);
  481. if (!msgval.array_val) return false;
  482. } else {
  483. if (!Convert_PhpToUpbAutoWrap(val, &msgval, TypeInfo_Get(f), arena)) {
  484. return false;
  485. }
  486. }
  487. upb_msg_set(msg, f, msgval, arena);
  488. zend_hash_move_forward_ex(table, &pos);
  489. zval_dtor(&key);
  490. }
  491. }
  492. static void Message_Initialize(Message *intern, const Descriptor *desc) {
  493. intern->desc = desc;
  494. intern->msg = upb_msg_new(desc->msgdef, Arena_Get(&intern->arena));
  495. ObjCache_Add(intern->msg, &intern->std);
  496. }
  497. /**
  498. * Message::__construct()
  499. *
  500. * Constructor for Message.
  501. * @param array Map of initial values ['k' = val]
  502. */
  503. PHP_METHOD(Message, __construct) {
  504. Message* intern = (Message*)Z_OBJ_P(getThis());
  505. const Descriptor* desc;
  506. zend_class_entry *ce = Z_OBJCE_P(getThis());
  507. upb_arena *arena = Arena_Get(&intern->arena);
  508. zval *init_arr = NULL;
  509. // This descriptor should always be available, as the generated __construct
  510. // method calls initOnce() to load the descriptor prior to calling us.
  511. //
  512. // However, if the user created their own class derived from Message, this
  513. // will trigger an infinite construction loop and blow the stack. We
  514. // temporarily clear create_object to break this loop (see check in
  515. // NameMap_GetMessage()).
  516. PBPHP_ASSERT(ce->create_object == Message_create);
  517. ce->create_object = NULL;
  518. desc = Descriptor_GetFromClassEntry(ce);
  519. ce->create_object = Message_create;
  520. if (!desc) {
  521. zend_throw_exception_ex(
  522. NULL, 0,
  523. "Couldn't find descriptor. Note only generated code may derive from "
  524. "\\Google\\Protobuf\\Internal\\Message");
  525. return;
  526. }
  527. Message_Initialize(intern, desc);
  528. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &init_arr) == FAILURE) {
  529. return;
  530. }
  531. if (init_arr) {
  532. Message_InitFromPhp(intern->msg, desc->msgdef, init_arr, arena);
  533. }
  534. }
  535. /**
  536. * Message::discardUnknownFields()
  537. *
  538. * Discards any unknown fields for this message or any submessages.
  539. */
  540. PHP_METHOD(Message, discardUnknownFields) {
  541. Message* intern = (Message*)Z_OBJ_P(getThis());
  542. upb_msg_discardunknown(intern->msg, intern->desc->msgdef, 64);
  543. }
  544. /**
  545. * Message::clear()
  546. *
  547. * Clears all fields of this message.
  548. */
  549. PHP_METHOD(Message, clear) {
  550. Message* intern = (Message*)Z_OBJ_P(getThis());
  551. upb_msg_clear(intern->msg, intern->desc->msgdef);
  552. }
  553. /**
  554. * Message::mergeFrom()
  555. *
  556. * Merges from the given message, which must be of the same class as us.
  557. * @param object Message to merge from.
  558. */
  559. PHP_METHOD(Message, mergeFrom) {
  560. Message* intern = (Message*)Z_OBJ_P(getThis());
  561. Message* from;
  562. upb_arena *arena = Arena_Get(&intern->arena);
  563. const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef);
  564. zval* value;
  565. char *pb;
  566. size_t size;
  567. bool ok;
  568. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &value,
  569. intern->desc->class_entry) == FAILURE) {
  570. return;
  571. }
  572. from = (Message*)Z_OBJ_P(value);
  573. // Should be guaranteed since we passed the class type to
  574. // zend_parse_parameters().
  575. PBPHP_ASSERT(from->desc == intern->desc);
  576. // TODO(haberman): use a temp arena for this once we can make upb_decode()
  577. // copy strings.
  578. pb = upb_encode(from->msg, l, arena, &size);
  579. if (!pb) {
  580. zend_throw_exception_ex(NULL, 0, "Max nesting exceeded");
  581. return;
  582. }
  583. ok = upb_decode(pb, size, intern->msg, l, arena);
  584. PBPHP_ASSERT(ok);
  585. }
  586. /**
  587. * Message::mergeFromString()
  588. *
  589. * Merges from the given string.
  590. * @param string Binary protobuf data to merge.
  591. */
  592. PHP_METHOD(Message, mergeFromString) {
  593. Message* intern = (Message*)Z_OBJ_P(getThis());
  594. char *data = NULL;
  595. char *data_copy = NULL;
  596. zend_long data_len;
  597. const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef);
  598. upb_arena *arena = Arena_Get(&intern->arena);
  599. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data, &data_len) ==
  600. FAILURE) {
  601. return;
  602. }
  603. // TODO(haberman): avoid this copy when we can make the decoder copy.
  604. data_copy = upb_arena_malloc(arena, data_len);
  605. memcpy(data_copy, data, data_len);
  606. if (!upb_decode(data_copy, data_len, intern->msg, l, arena)) {
  607. zend_throw_exception_ex(NULL, 0, "Error occurred during parsing");
  608. return;
  609. }
  610. }
  611. /**
  612. * Message::serializeToString()
  613. *
  614. * Serializes this message instance to protobuf data.
  615. * @return string Serialized protobuf data.
  616. */
  617. PHP_METHOD(Message, serializeToString) {
  618. Message* intern = (Message*)Z_OBJ_P(getThis());
  619. const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef);
  620. upb_arena *tmp_arena = upb_arena_new();
  621. char *data;
  622. size_t size;
  623. data = upb_encode(intern->msg, l, tmp_arena, &size);
  624. if (!data) {
  625. zend_throw_exception_ex(NULL, 0, "Error occurred during serialization");
  626. upb_arena_free(tmp_arena);
  627. return;
  628. }
  629. RETVAL_STRINGL(data, size);
  630. upb_arena_free(tmp_arena);
  631. }
  632. /**
  633. * Message::mergeFromJsonString()
  634. *
  635. * Merges the JSON data parsed from the given string.
  636. * @param string Serialized JSON data.
  637. */
  638. PHP_METHOD(Message, mergeFromJsonString) {
  639. Message* intern = (Message*)Z_OBJ_P(getThis());
  640. char *data = NULL;
  641. char *data_copy = NULL;
  642. zend_long data_len;
  643. upb_arena *arena = Arena_Get(&intern->arena);
  644. upb_status status;
  645. zend_bool ignore_json_unknown = false;
  646. int options = 0;
  647. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &data, &data_len,
  648. &ignore_json_unknown) == FAILURE) {
  649. return;
  650. }
  651. // TODO(haberman): avoid this copy when we can make the decoder copy.
  652. data_copy = upb_arena_malloc(arena, data_len + 1);
  653. memcpy(data_copy, data, data_len);
  654. data_copy[data_len] = '\0';
  655. if (ignore_json_unknown) {
  656. options |= UPB_JSONDEC_IGNOREUNKNOWN;
  657. }
  658. upb_status_clear(&status);
  659. if (!upb_json_decode(data_copy, data_len, intern->msg, intern->desc->msgdef,
  660. DescriptorPool_GetSymbolTable(), options, arena,
  661. &status)) {
  662. zend_throw_exception_ex(NULL, 0, "Error occurred during parsing: %s",
  663. upb_status_errmsg(&status));
  664. return;
  665. }
  666. }
  667. /**
  668. * Message::serializeToJsonString()
  669. *
  670. * Serializes this object to JSON.
  671. * @return string Serialized JSON data.
  672. */
  673. PHP_METHOD(Message, serializeToJsonString) {
  674. Message* intern = (Message*)Z_OBJ_P(getThis());
  675. size_t size;
  676. int options = 0;
  677. char buf[1024];
  678. zend_bool preserve_proto_fieldnames = false;
  679. upb_status status;
  680. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b",
  681. &preserve_proto_fieldnames) == FAILURE) {
  682. return;
  683. }
  684. if (preserve_proto_fieldnames) {
  685. options |= UPB_JSONENC_PROTONAMES;
  686. }
  687. upb_status_clear(&status);
  688. size = upb_json_encode(intern->msg, intern->desc->msgdef,
  689. DescriptorPool_GetSymbolTable(), options, buf,
  690. sizeof(buf), &status);
  691. if (!upb_ok(&status)) {
  692. zend_throw_exception_ex(NULL, 0,
  693. "Error occurred during JSON serialization: %s",
  694. upb_status_errmsg(&status));
  695. return;
  696. }
  697. if (size >= sizeof(buf)) {
  698. char *buf2 = malloc(size + 1);
  699. upb_json_encode(intern->msg, intern->desc->msgdef,
  700. DescriptorPool_GetSymbolTable(), options, buf2, size + 1,
  701. &status);
  702. RETVAL_STRINGL(buf2, size);
  703. free(buf2);
  704. } else {
  705. RETVAL_STRINGL(buf, size);
  706. }
  707. }
  708. /**
  709. * Message::readWrapperValue()
  710. *
  711. * Returns an unboxed value for the given field. This is called from generated
  712. * methods for wrapper fields, eg.
  713. *
  714. * public function getDoubleValueUnwrapped()
  715. * {
  716. * return $this->readWrapperValue("double_value");
  717. * }
  718. *
  719. * @return Unwrapped field value or null.
  720. */
  721. PHP_METHOD(Message, readWrapperValue) {
  722. Message* intern = (Message*)Z_OBJ_P(getThis());
  723. char* member;
  724. const upb_fielddef *f;
  725. zend_long size;
  726. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &member, &size) == FAILURE) {
  727. return;
  728. }
  729. f = upb_msgdef_ntof(intern->desc->msgdef, member, size);
  730. if (!f || !upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f))) {
  731. zend_throw_exception_ex(NULL, 0, "Message %s has no field %s",
  732. upb_msgdef_fullname(intern->desc->msgdef), member);
  733. return;
  734. }
  735. if (upb_msg_has(intern->msg, f)) {
  736. const upb_msg *wrapper = upb_msg_get(intern->msg, f).msg_val;
  737. const upb_msgdef *m = upb_fielddef_msgsubdef(f);
  738. const upb_fielddef *val_f = upb_msgdef_itof(m, 1);
  739. upb_msgval msgval = upb_msg_get(wrapper, val_f);
  740. zval ret;
  741. Convert_UpbToPhp(msgval, &ret, TypeInfo_Get(val_f), &intern->arena);
  742. RETURN_ZVAL(&ret, 1, 0);
  743. } else {
  744. RETURN_NULL();
  745. }
  746. }
  747. /**
  748. * Message::writeWrapperValue()
  749. *
  750. * Sets the given wrapper field to the given unboxed value. This is called from
  751. * generated methods for wrapper fields, eg.
  752. *
  753. *
  754. * public function setDoubleValueUnwrapped($var)
  755. * {
  756. * $this->writeWrapperValue("double_value", $var);
  757. * return $this;
  758. * }
  759. *
  760. * @param Unwrapped field value or null.
  761. */
  762. PHP_METHOD(Message, writeWrapperValue) {
  763. Message* intern = (Message*)Z_OBJ_P(getThis());
  764. upb_arena *arena = Arena_Get(&intern->arena);
  765. char* member;
  766. const upb_fielddef *f;
  767. upb_msgval msgval;
  768. zend_long size;
  769. zval* val;
  770. if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &member, &size, &val) ==
  771. FAILURE) {
  772. return;
  773. }
  774. f = upb_msgdef_ntof(intern->desc->msgdef, member, size);
  775. if (!f || !upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f))) {
  776. zend_throw_exception_ex(NULL, 0, "Message %s has no field %s",
  777. upb_msgdef_fullname(intern->desc->msgdef), member);
  778. return;
  779. }
  780. if (Z_ISREF_P(val)) {
  781. ZVAL_DEREF(val);
  782. }
  783. if (Z_TYPE_P(val) == IS_NULL) {
  784. upb_msg_clearfield(intern->msg, f);
  785. } else {
  786. const upb_msgdef *m = upb_fielddef_msgsubdef(f);
  787. const upb_fielddef *val_f = upb_msgdef_itof(m, 1);
  788. upb_msg *wrapper;
  789. if (!Convert_PhpToUpb(val, &msgval, TypeInfo_Get(val_f), arena)) {
  790. return; // Error is already set.
  791. }
  792. wrapper = upb_msg_mutable(intern->msg, f, arena).msg;
  793. upb_msg_set(wrapper, val_f, msgval, arena);
  794. }
  795. }
  796. /**
  797. * Message::whichOneof()
  798. *
  799. * Given a oneof name, returns the name of the field that is set for this oneof,
  800. * or otherwise the empty string.
  801. *
  802. * @return string The field name in this oneof that is currently set.
  803. */
  804. PHP_METHOD(Message, whichOneof) {
  805. Message* intern = (Message*)Z_OBJ_P(getThis());
  806. const upb_oneofdef* oneof;
  807. const upb_fielddef* field;
  808. char* name;
  809. zend_long len;
  810. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &len) == FAILURE) {
  811. return;
  812. }
  813. oneof = upb_msgdef_ntoo(intern->desc->msgdef, name, len);
  814. if (!oneof) {
  815. zend_throw_exception_ex(NULL, 0, "Message %s has no oneof %s",
  816. upb_msgdef_fullname(intern->desc->msgdef), name);
  817. return;
  818. }
  819. field = upb_msg_whichoneof(intern->msg, oneof);
  820. RETURN_STRING(field ? upb_fielddef_name(field) : "");
  821. }
  822. /**
  823. * Message::hasOneof()
  824. *
  825. * Returns the presence of the given oneof field, given a field number. Called
  826. * from generated code methods such as:
  827. *
  828. * public function hasDoubleValueOneof()
  829. * {
  830. * return $this->hasOneof(10);
  831. * }
  832. *
  833. * @return boolean
  834. */
  835. PHP_METHOD(Message, hasOneof) {
  836. Message* intern = (Message*)Z_OBJ_P(getThis());
  837. zend_long field_num;
  838. const upb_fielddef* f;
  839. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &field_num) == FAILURE) {
  840. return;
  841. }
  842. f = upb_msgdef_itof(intern->desc->msgdef, field_num);
  843. if (!f || !upb_fielddef_realcontainingoneof(f)) {
  844. php_error_docref(NULL, E_USER_ERROR,
  845. "Internal error, no such oneof field %d\n",
  846. (int)field_num);
  847. }
  848. RETVAL_BOOL(upb_msg_has(intern->msg, f));
  849. }
  850. /**
  851. * Message::readOneof()
  852. *
  853. * Returns the contents of the given oneof field, given a field number. Called
  854. * from generated code methods such as:
  855. *
  856. * public function getDoubleValueOneof()
  857. * {
  858. * return $this->readOneof(10);
  859. * }
  860. *
  861. * @return object The oneof's field value.
  862. */
  863. PHP_METHOD(Message, readOneof) {
  864. Message* intern = (Message*)Z_OBJ_P(getThis());
  865. zend_long field_num;
  866. const upb_fielddef* f;
  867. zval ret;
  868. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &field_num) == FAILURE) {
  869. return;
  870. }
  871. f = upb_msgdef_itof(intern->desc->msgdef, field_num);
  872. if (!f || !upb_fielddef_realcontainingoneof(f)) {
  873. php_error_docref(NULL, E_USER_ERROR,
  874. "Internal error, no such oneof field %d\n",
  875. (int)field_num);
  876. }
  877. if (upb_fielddef_issubmsg(f) && !upb_msg_has(intern->msg, f)) {
  878. RETURN_NULL();
  879. }
  880. {
  881. upb_msgval msgval = upb_msg_get(intern->msg, f);
  882. Convert_UpbToPhp(msgval, &ret, TypeInfo_Get(f), &intern->arena);
  883. }
  884. RETURN_ZVAL(&ret, 1, 0);
  885. }
  886. /**
  887. * Message::writeOneof()
  888. *
  889. * Sets the contents of the given oneof field, given a field number. Called
  890. * from generated code methods such as:
  891. *
  892. * public function setDoubleValueOneof($var)
  893. * {
  894. * GPBUtil::checkMessage($var, \Google\Protobuf\DoubleValue::class);
  895. * $this->writeOneof(10, $var);
  896. *
  897. * return $this;
  898. * }
  899. *
  900. * The C extension version of GPBUtil::check*() does nothing, so we perform
  901. * all type checking and conversion here.
  902. *
  903. * @param integer The field number we are setting.
  904. * @param object The field value we want to set.
  905. */
  906. PHP_METHOD(Message, writeOneof) {
  907. Message* intern = (Message*)Z_OBJ_P(getThis());
  908. zend_long field_num;
  909. const upb_fielddef* f;
  910. upb_arena *arena = Arena_Get(&intern->arena);
  911. upb_msgval msgval;
  912. zval* val;
  913. if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &field_num, &val) ==
  914. FAILURE) {
  915. return;
  916. }
  917. f = upb_msgdef_itof(intern->desc->msgdef, field_num);
  918. if (!Convert_PhpToUpb(val, &msgval, TypeInfo_Get(f), arena)) {
  919. return;
  920. }
  921. upb_msg_set(intern->msg, f, msgval, arena);
  922. }
  923. ZEND_BEGIN_ARG_INFO_EX(arginfo_mergeFrom, 0, 0, 1)
  924. ZEND_ARG_INFO(0, data)
  925. ZEND_END_ARG_INFO()
  926. ZEND_BEGIN_ARG_INFO_EX(arginfo_read, 0, 0, 1)
  927. ZEND_ARG_INFO(0, field)
  928. ZEND_END_ARG_INFO()
  929. ZEND_BEGIN_ARG_INFO_EX(arginfo_write, 0, 0, 2)
  930. ZEND_ARG_INFO(0, field)
  931. ZEND_ARG_INFO(0, value)
  932. ZEND_END_ARG_INFO()
  933. static zend_function_entry Message_methods[] = {
  934. PHP_ME(Message, clear, arginfo_void, ZEND_ACC_PUBLIC)
  935. PHP_ME(Message, discardUnknownFields, arginfo_void, ZEND_ACC_PUBLIC)
  936. PHP_ME(Message, serializeToString, arginfo_void, ZEND_ACC_PUBLIC)
  937. PHP_ME(Message, mergeFromString, arginfo_mergeFrom, ZEND_ACC_PUBLIC)
  938. PHP_ME(Message, serializeToJsonString, arginfo_void, ZEND_ACC_PUBLIC)
  939. PHP_ME(Message, mergeFromJsonString, arginfo_mergeFrom, ZEND_ACC_PUBLIC)
  940. PHP_ME(Message, mergeFrom, arginfo_mergeFrom, ZEND_ACC_PUBLIC)
  941. PHP_ME(Message, readWrapperValue, arginfo_read, ZEND_ACC_PROTECTED)
  942. PHP_ME(Message, writeWrapperValue, arginfo_write, ZEND_ACC_PROTECTED)
  943. PHP_ME(Message, hasOneof, arginfo_read, ZEND_ACC_PROTECTED)
  944. PHP_ME(Message, readOneof, arginfo_read, ZEND_ACC_PROTECTED)
  945. PHP_ME(Message, writeOneof, arginfo_write, ZEND_ACC_PROTECTED)
  946. PHP_ME(Message, whichOneof, arginfo_read, ZEND_ACC_PROTECTED)
  947. PHP_ME(Message, __construct, arginfo_void, ZEND_ACC_PROTECTED)
  948. ZEND_FE_END
  949. };
  950. // Well-known types ////////////////////////////////////////////////////////////
  951. static const char TYPE_URL_PREFIX[] = "type.googleapis.com/";
  952. static upb_msgval Message_getval(Message *intern, const char *field_name) {
  953. const upb_fielddef *f = upb_msgdef_ntofz(intern->desc->msgdef, field_name);
  954. PBPHP_ASSERT(f);
  955. return upb_msg_get(intern->msg, f);
  956. }
  957. static void Message_setval(Message *intern, const char *field_name,
  958. upb_msgval val) {
  959. const upb_fielddef *f = upb_msgdef_ntofz(intern->desc->msgdef, field_name);
  960. PBPHP_ASSERT(f);
  961. return upb_msg_set(intern->msg, f, val, Arena_Get(&intern->arena));
  962. }
  963. static upb_msgval StringVal(upb_strview view) {
  964. upb_msgval ret;
  965. ret.str_val = view;
  966. return ret;
  967. }
  968. static bool TryStripUrlPrefix(upb_strview *str) {
  969. size_t size = strlen(TYPE_URL_PREFIX);
  970. if (str->size < size || memcmp(TYPE_URL_PREFIX, str->data, size) != 0) {
  971. return false;
  972. }
  973. str->data += size;
  974. str->size -= size;
  975. return true;
  976. }
  977. static bool StrViewEq(upb_strview view, const char *str) {
  978. size_t size = strlen(str);
  979. return view.size == size && memcmp(view.data, str, size) == 0;
  980. }
  981. PHP_METHOD(google_protobuf_Any, unpack) {
  982. Message* intern = (Message*)Z_OBJ_P(getThis());
  983. upb_strview type_url = Message_getval(intern, "type_url").str_val;
  984. upb_strview value = Message_getval(intern, "value").str_val;
  985. upb_symtab *symtab = DescriptorPool_GetSymbolTable();
  986. const upb_msgdef *m;
  987. Descriptor *desc;
  988. zval ret;
  989. // Ensure that type_url has TYPE_URL_PREFIX as a prefix.
  990. if (!TryStripUrlPrefix(&type_url)) {
  991. zend_throw_exception(
  992. NULL, "Type url needs to be type.googleapis.com/fully-qualified",
  993. 0);
  994. return;
  995. }
  996. m = upb_symtab_lookupmsg2(symtab, type_url.data, type_url.size);
  997. if (m == NULL) {
  998. zend_throw_exception(
  999. NULL, "Specified message in any hasn't been added to descriptor pool",
  1000. 0);
  1001. return;
  1002. }
  1003. desc = Descriptor_GetFromMessageDef(m);
  1004. PBPHP_ASSERT(desc->class_entry->create_object == Message_create);
  1005. zend_object *obj = Message_create(desc->class_entry);
  1006. Message *msg = (Message*)obj;
  1007. Message_Initialize(msg, desc);
  1008. ZVAL_OBJ(&ret, obj);
  1009. // Get value.
  1010. if (!upb_decode(value.data, value.size, msg->msg,
  1011. upb_msgdef_layout(desc->msgdef), Arena_Get(&msg->arena))) {
  1012. zend_throw_exception_ex(NULL, 0, "Error occurred during parsing");
  1013. return;
  1014. }
  1015. // Fuse since the parsed message could alias "value".
  1016. upb_arena_fuse(Arena_Get(&intern->arena), Arena_Get(&msg->arena));
  1017. RETURN_ZVAL(&ret, 1, 0);
  1018. }
  1019. PHP_METHOD(google_protobuf_Any, pack) {
  1020. Message* intern = (Message*)Z_OBJ_P(getThis());
  1021. upb_arena *arena = Arena_Get(&intern->arena);
  1022. zval *val;
  1023. Message *msg;
  1024. upb_strview value;
  1025. upb_strview type_url;
  1026. const char *full_name;
  1027. char *buf;
  1028. if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &val) ==
  1029. FAILURE) {
  1030. return;
  1031. }
  1032. if (!instanceof_function(Z_OBJCE_P(val), message_ce)) {
  1033. zend_error(E_USER_ERROR, "Given value is not an instance of Message.");
  1034. return;
  1035. }
  1036. msg = (Message*)Z_OBJ_P(val);
  1037. // Serialize and set value.
  1038. value.data = upb_encode(msg->msg, upb_msgdef_layout(msg->desc->msgdef), arena,
  1039. &value.size);
  1040. Message_setval(intern, "value", StringVal(value));
  1041. // Set type url: type_url_prefix + fully_qualified_name
  1042. full_name = upb_msgdef_fullname(msg->desc->msgdef);
  1043. type_url.size = strlen(TYPE_URL_PREFIX) + strlen(full_name);
  1044. buf = upb_arena_malloc(arena, type_url.size + 1);
  1045. memcpy(buf, TYPE_URL_PREFIX, strlen(TYPE_URL_PREFIX));
  1046. memcpy(buf + strlen(TYPE_URL_PREFIX), full_name, strlen(full_name));
  1047. type_url.data = buf;
  1048. Message_setval(intern, "type_url", StringVal(type_url));
  1049. }
  1050. PHP_METHOD(google_protobuf_Any, is) {
  1051. Message* intern = (Message*)Z_OBJ_P(getThis());
  1052. upb_strview type_url = Message_getval(intern, "type_url").str_val;
  1053. zend_class_entry *klass = NULL;
  1054. const upb_msgdef *m;
  1055. if (zend_parse_parameters(ZEND_NUM_ARGS(), "C", &klass) ==
  1056. FAILURE) {
  1057. return;
  1058. }
  1059. m = NameMap_GetMessage(klass);
  1060. if (m == NULL) {
  1061. RETURN_BOOL(false);
  1062. }
  1063. RETURN_BOOL(TryStripUrlPrefix(&type_url) &&
  1064. StrViewEq(type_url, upb_msgdef_fullname(m)));
  1065. }
  1066. PHP_METHOD(google_protobuf_Timestamp, fromDateTime) {
  1067. Message* intern = (Message*)Z_OBJ_P(getThis());
  1068. zval* datetime;
  1069. const char *classname = "\\DatetimeInterface";
  1070. zend_string *classname_str = zend_string_init(classname, strlen(classname), 0);
  1071. zend_class_entry *date_interface_ce = zend_lookup_class(classname_str);
  1072. if (date_interface_ce == NULL) {
  1073. zend_error(E_ERROR, "Make sure date extension is enabled.");
  1074. return;
  1075. }
  1076. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &datetime,
  1077. date_interface_ce) == FAILURE) {
  1078. zend_error(E_USER_ERROR, "Expect DatetimeInterface.");
  1079. return;
  1080. }
  1081. upb_msgval timestamp_seconds;
  1082. {
  1083. zval retval;
  1084. zval function_name;
  1085. ZVAL_STRING(&function_name, "date_timestamp_get");
  1086. if (call_user_function(EG(function_table), NULL, &function_name, &retval, 1,
  1087. datetime) == FAILURE ||
  1088. !Convert_PhpToUpb(&retval, &timestamp_seconds,
  1089. TypeInfo_FromType(UPB_TYPE_INT64), NULL)) {
  1090. zend_error(E_ERROR, "Cannot get timestamp from DateTime.");
  1091. return;
  1092. }
  1093. zval_dtor(&retval);
  1094. zval_dtor(&function_name);
  1095. }
  1096. upb_msgval timestamp_nanos;
  1097. {
  1098. zval retval;
  1099. zval function_name;
  1100. zval format_string;
  1101. ZVAL_STRING(&function_name, "date_format");
  1102. ZVAL_STRING(&format_string, "u");
  1103. zval params[2] = {
  1104. *datetime,
  1105. format_string,
  1106. };
  1107. if (call_user_function(EG(function_table), NULL, &function_name, &retval, 2,
  1108. params) == FAILURE ||
  1109. !Convert_PhpToUpb(&retval, &timestamp_nanos,
  1110. TypeInfo_FromType(UPB_TYPE_INT32), NULL)) {
  1111. zend_error(E_ERROR, "Cannot format DateTime.");
  1112. return;
  1113. }
  1114. timestamp_nanos.int32_val *= 1000;
  1115. zval_dtor(&retval);
  1116. zval_dtor(&function_name);
  1117. zval_dtor(&format_string);
  1118. }
  1119. Message_setval(intern, "seconds", timestamp_seconds);
  1120. Message_setval(intern, "nanos", timestamp_nanos);
  1121. RETURN_NULL();
  1122. }
  1123. PHP_METHOD(google_protobuf_Timestamp, toDateTime) {
  1124. Message* intern = (Message*)Z_OBJ_P(getThis());
  1125. upb_msgval seconds = Message_getval(intern, "seconds");
  1126. upb_msgval nanos = Message_getval(intern, "nanos");
  1127. // Get formatted time string.
  1128. char formatted_time[32];
  1129. snprintf(formatted_time, sizeof(formatted_time), "%" PRId64 ".%06" PRId32,
  1130. seconds.int64_val, nanos.int32_val / 1000);
  1131. // Create Datetime object.
  1132. zval datetime;
  1133. zval function_name;
  1134. zval format_string;
  1135. zval formatted_time_php;
  1136. ZVAL_STRING(&function_name, "date_create_from_format");
  1137. ZVAL_STRING(&format_string, "U.u");
  1138. ZVAL_STRING(&formatted_time_php, formatted_time);
  1139. zval params[2] = {
  1140. format_string,
  1141. formatted_time_php,
  1142. };
  1143. if (call_user_function(EG(function_table), NULL, &function_name, &datetime, 2,
  1144. params) == FAILURE) {
  1145. zend_error(E_ERROR, "Cannot create DateTime.");
  1146. return;
  1147. }
  1148. zval_dtor(&function_name);
  1149. zval_dtor(&format_string);
  1150. zval_dtor(&formatted_time_php);
  1151. ZVAL_OBJ(return_value, Z_OBJ(datetime));
  1152. }
  1153. #include "wkt.inc"
  1154. /**
  1155. * Message_ModuleInit()
  1156. *
  1157. * Called when the C extension is loaded to register all types.
  1158. */
  1159. void Message_ModuleInit() {
  1160. zend_class_entry tmp_ce;
  1161. zend_object_handlers *h = &message_object_handlers;
  1162. INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\Message",
  1163. Message_methods);
  1164. message_ce = zend_register_internal_class(&tmp_ce);
  1165. message_ce->create_object = Message_create;
  1166. memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
  1167. h->dtor_obj = Message_dtor;
  1168. #if PHP_VERSION_ID < 80000
  1169. h->compare_objects = Message_compare_objects;
  1170. #else
  1171. h->compare = Message_compare_objects;
  1172. #endif
  1173. h->read_property = Message_read_property;
  1174. h->write_property = Message_write_property;
  1175. h->has_property = Message_has_property;
  1176. h->unset_property = Message_unset_property;
  1177. h->get_properties = Message_get_properties;
  1178. h->get_property_ptr_ptr = Message_get_property_ptr_ptr;
  1179. h->clone_obj = Message_clone_obj;
  1180. WellKnownTypes_ModuleInit(); /* From wkt.inc. */
  1181. }