message.c 39 KB

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