PageRenderTime 150ms CodeModel.GetById 28ms RepoModel.GetById 7ms app.codeStats 2ms

/hphp/runtime/ext/soap/encoding.cpp

http://github.com/facebook/hiphop-php
C++ | 3387 lines | 3002 code | 264 blank | 121 comment | 1044 complexity | bc0bc2ca297648bf6f5ac1fc937780d3 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, MIT, LGPL-2.0, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
  6. | Copyright (c) 1997-2010 The PHP Group |
  7. +----------------------------------------------------------------------+
  8. | This source file is subject to version 3.01 of the PHP license, |
  9. | that is bundled with this package in the file LICENSE, and is |
  10. | available through the world-wide-web at the following url: |
  11. | http://www.php.net/license/3_01.txt |
  12. | If you did not receive a copy of the PHP license and are unable to |
  13. | obtain it through the world-wide-web, please send a note to |
  14. | license@php.net so we can mail you a copy immediately. |
  15. +----------------------------------------------------------------------+
  16. */
  17. #include "hphp/runtime/ext/soap/encoding.h"
  18. #include <cstdlib>
  19. #include <map>
  20. #include <memory>
  21. #include <folly/Conv.h>
  22. #include "hphp/runtime/ext/soap/ext_soap.h"
  23. #include "hphp/runtime/ext/soap/soap.h"
  24. #include "hphp/runtime/ext/string/ext_string.h"
  25. #include "hphp/runtime/base/array-init.h"
  26. #include "hphp/runtime/base/array-iterator.h"
  27. #include "hphp/runtime/base/zend-functions.h"
  28. #include "hphp/runtime/base/comparisons.h"
  29. #include "hphp/runtime/base/string-buffer.h"
  30. #include "hphp/runtime/base/string-util.h"
  31. #include "hphp/runtime/base/type-array.h"
  32. #include "hphp/runtime/vm/native-data.h"
  33. namespace HPHP {
  34. ///////////////////////////////////////////////////////////////////////////////
  35. using std::string;
  36. using std::abs;
  37. bool php_libxml_xmlCheckUTF8(const unsigned char *s) {
  38. int i;
  39. unsigned char c;
  40. for (i = 0; (c = s[i++]);) {
  41. if ((c & 0x80) == 0) {
  42. } else if ((c & 0xe0) == 0xc0) {
  43. if ((s[i++] & 0xc0) != 0x80) {
  44. return false;
  45. }
  46. } else if ((c & 0xf0) == 0xe0) {
  47. if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
  48. return false;
  49. }
  50. } else if ((c & 0xf8) == 0xf0) {
  51. if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80 ||
  52. (s[i++] & 0xc0) != 0x80) {
  53. return false;
  54. }
  55. } else {
  56. return false;
  57. }
  58. }
  59. return true;
  60. }
  61. static int zend_strnlen(const char* s, int maxlen) {
  62. int len = 0;
  63. while (*s++ && maxlen--) len++;
  64. return len;
  65. }
  66. static bool zend_unmangle_property_name(const char *mangled_property, int len,
  67. const char **class_name,
  68. const char **prop_name) {
  69. int class_name_len;
  70. *class_name = nullptr;
  71. if (mangled_property[0]!=0) {
  72. *prop_name = mangled_property;
  73. return true;
  74. }
  75. if (len < 3 || mangled_property[1]==0) {
  76. raise_warning("Illegal member variable name");
  77. *prop_name = mangled_property;
  78. return false;
  79. }
  80. class_name_len = zend_strnlen(mangled_property+1, --len - 1) + 1;
  81. if (class_name_len >= len || mangled_property[class_name_len]!=0) {
  82. raise_warning("Corrupt member variable name");
  83. *prop_name = mangled_property;
  84. return false;
  85. }
  86. *class_name = mangled_property+1;
  87. *prop_name = (*class_name)+class_name_len;
  88. return true;
  89. }
  90. ///////////////////////////////////////////////////////////////////////////////
  91. static Variant to_zval_double (encodeType* type, xmlNodePtr data);
  92. static Variant to_zval_long (encodeType* type, xmlNodePtr data);
  93. static Variant to_zval_bool (encodeType* type, xmlNodePtr data);
  94. static Variant to_zval_string (encodeType* type, xmlNodePtr data);
  95. static Variant to_zval_stringr (encodeType* type, xmlNodePtr data);
  96. static Variant to_zval_stringc (encodeType* type, xmlNodePtr data);
  97. static Variant to_zval_map (encodeType* type, xmlNodePtr data);
  98. static Variant to_zval_null (encodeType* type, xmlNodePtr data);
  99. static Variant to_zval_base64 (encodeType* type, xmlNodePtr data);
  100. static Variant to_zval_hexbin (encodeType* type, xmlNodePtr data);
  101. static xmlNodePtr to_xml_long
  102. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  103. static xmlNodePtr to_xml_double
  104. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  105. static xmlNodePtr to_xml_bool
  106. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  107. /* String encode */
  108. static xmlNodePtr to_xml_string
  109. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  110. static xmlNodePtr to_xml_base64
  111. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  112. static xmlNodePtr to_xml_hexbin
  113. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  114. /* Null encode */
  115. static xmlNodePtr to_xml_null
  116. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  117. /* Array encode */
  118. static xmlNodePtr guess_array_map
  119. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  120. static xmlNodePtr to_xml_map
  121. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  122. static xmlNodePtr to_xml_list
  123. (encodeType* enc, const Variant& data, int style, xmlNodePtr parent);
  124. static xmlNodePtr to_xml_list1
  125. (encodeType* enc, const Variant& data, int style, xmlNodePtr parent);
  126. /* Datetime encode/decode */
  127. static xmlNodePtr to_xml_datetime_ex
  128. (encodeType* type, const Variant& data, const char *format, int style,
  129. xmlNodePtr parent);
  130. static xmlNodePtr to_xml_datetime
  131. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  132. static xmlNodePtr to_xml_time
  133. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  134. static xmlNodePtr to_xml_date
  135. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  136. static xmlNodePtr to_xml_gyearmonth
  137. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  138. static xmlNodePtr to_xml_gyear
  139. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  140. static xmlNodePtr to_xml_gmonthday
  141. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  142. static xmlNodePtr to_xml_gday
  143. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  144. static xmlNodePtr to_xml_gmonth
  145. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  146. static xmlNodePtr to_xml_duration
  147. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  148. static Variant to_zval_object(encodeType* type, xmlNodePtr data);
  149. static Variant to_zval_array(encodeType* type, xmlNodePtr data);
  150. static xmlNodePtr to_xml_object
  151. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  152. static xmlNodePtr to_xml_array
  153. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  154. static Variant to_zval_any
  155. (encodeType* type, xmlNodePtr data);
  156. static xmlNodePtr to_xml_any
  157. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  158. /* Try and guess for non-wsdl clients and servers */
  159. static Variant guess_zval_convert
  160. (encodeType* type, xmlNodePtr data);
  161. static xmlNodePtr guess_xml_convert
  162. (encodeType* type, const Variant& data, int style, xmlNodePtr parent);
  163. static encodePtr get_array_type
  164. (xmlNodePtr node, const Variant& array, string &out_type);
  165. static xmlNodePtr check_and_resolve_href(xmlNodePtr data);
  166. static void set_ns_prop(xmlNodePtr node, const char *ns, const char *name,
  167. const char *val);
  168. static void set_xsi_nil(xmlNodePtr node);
  169. static void set_xsi_type(xmlNodePtr node, const char *type);
  170. static void get_type_str
  171. (xmlNodePtr node, const char* ns, const char* type, string &ret);
  172. static void set_ns_and_type_ex(xmlNodePtr node, const char *ns,
  173. const char *type);
  174. static void set_ns_and_type(xmlNodePtr node, encodeType* type);
  175. #define FIND_XML_NULL(xml, v) \
  176. { \
  177. if (!xml) { \
  178. v = init_null(); \
  179. return v; \
  180. } \
  181. if (xml->properties) { \
  182. xmlAttrPtr n = get_attribute(xml->properties, "nil"); \
  183. if (n) { \
  184. v = init_null(); \
  185. return v; \
  186. } \
  187. } \
  188. }
  189. #define CHECK_XML_NULL(xml) \
  190. { \
  191. if (!xml) { \
  192. return uninit_null(); \
  193. } \
  194. if (xml->properties) { \
  195. xmlAttrPtr n = get_attribute(xml->properties, "nil"); \
  196. if (n) { \
  197. return uninit_null(); \
  198. } \
  199. } \
  200. }
  201. #define FIND_ZVAL_NULL(v, xml, style) \
  202. { \
  203. if (v.isNull()) { \
  204. if (style == SOAP_ENCODED) { \
  205. set_xsi_nil(xml); \
  206. } \
  207. return xml; \
  208. } \
  209. }
  210. ///////////////////////////////////////////////////////////////////////////////
  211. encodeStatic s_defaultEncoding[] = {
  212. {UNKNOWN_TYPE, "", "", guess_zval_convert, guess_xml_convert},
  213. {SOAP_ENC_NULL_DT, SOAP_ENC_NULL_DT_STRING, XSI_NAMESPACE,
  214. to_zval_null, to_xml_null},
  215. {XSD_STRING, XSD_STRING_STRING, XSD_NAMESPACE,
  216. to_zval_string, to_xml_string},
  217. {XSD_BOOLEAN, XSD_BOOLEAN_STRING, XSD_NAMESPACE,
  218. to_zval_bool, to_xml_bool},
  219. {XSD_DECIMAL, XSD_DECIMAL_STRING, XSD_NAMESPACE,
  220. to_zval_stringc, to_xml_string},
  221. {XSD_FLOAT, XSD_FLOAT_STRING, XSD_NAMESPACE,
  222. to_zval_double, to_xml_double},
  223. {XSD_DOUBLE, XSD_DOUBLE_STRING, XSD_NAMESPACE,
  224. to_zval_double, to_xml_double},
  225. {XSD_DATETIME, XSD_DATETIME_STRING, XSD_NAMESPACE,
  226. to_zval_stringc, to_xml_datetime},
  227. {XSD_TIME, XSD_TIME_STRING, XSD_NAMESPACE,
  228. to_zval_stringc, to_xml_time},
  229. {XSD_DATE, XSD_DATE_STRING, XSD_NAMESPACE,
  230. to_zval_stringc, to_xml_date},
  231. {XSD_GYEARMONTH, XSD_GYEARMONTH_STRING, XSD_NAMESPACE,
  232. to_zval_stringc, to_xml_gyearmonth},
  233. {XSD_GYEAR, XSD_GYEAR_STRING, XSD_NAMESPACE,
  234. to_zval_stringc, to_xml_gyear},
  235. {XSD_GMONTHDAY, XSD_GMONTHDAY_STRING, XSD_NAMESPACE,
  236. to_zval_stringc, to_xml_gmonthday},
  237. {XSD_GDAY, XSD_GDAY_STRING, XSD_NAMESPACE,
  238. to_zval_stringc, to_xml_gday},
  239. {XSD_GMONTH, XSD_GMONTH_STRING, XSD_NAMESPACE,
  240. to_zval_stringc, to_xml_gmonth},
  241. {XSD_DURATION, XSD_DURATION_STRING, XSD_NAMESPACE,
  242. to_zval_stringc, to_xml_duration},
  243. {XSD_HEXBINARY, XSD_HEXBINARY_STRING, XSD_NAMESPACE,
  244. to_zval_hexbin, to_xml_hexbin},
  245. {XSD_BASE64BINARY, XSD_BASE64BINARY_STRING, XSD_NAMESPACE,
  246. to_zval_base64, to_xml_base64},
  247. {XSD_LONG, XSD_LONG_STRING, XSD_NAMESPACE,
  248. to_zval_long, to_xml_long},
  249. {XSD_INT, XSD_INT_STRING, XSD_NAMESPACE,
  250. to_zval_long, to_xml_long},
  251. {XSD_SHORT, XSD_SHORT_STRING, XSD_NAMESPACE,
  252. to_zval_long, to_xml_long},
  253. {XSD_BYTE, XSD_BYTE_STRING, XSD_NAMESPACE,
  254. to_zval_long, to_xml_long},
  255. {XSD_NONPOSITIVEINTEGER,XSD_NONPOSITIVEINTEGER_STRING,XSD_NAMESPACE,
  256. to_zval_long, to_xml_long},
  257. {XSD_POSITIVEINTEGER, XSD_POSITIVEINTEGER_STRING, XSD_NAMESPACE,
  258. to_zval_long, to_xml_long},
  259. {XSD_NONNEGATIVEINTEGER,XSD_NONNEGATIVEINTEGER_STRING,XSD_NAMESPACE,
  260. to_zval_long, to_xml_long},
  261. {XSD_NEGATIVEINTEGER, XSD_NEGATIVEINTEGER_STRING, XSD_NAMESPACE,
  262. to_zval_long, to_xml_long},
  263. {XSD_UNSIGNEDBYTE, XSD_UNSIGNEDBYTE_STRING, XSD_NAMESPACE,
  264. to_zval_long, to_xml_long},
  265. {XSD_UNSIGNEDSHORT, XSD_UNSIGNEDSHORT_STRING, XSD_NAMESPACE,
  266. to_zval_long, to_xml_long},
  267. {XSD_UNSIGNEDINT, XSD_UNSIGNEDINT_STRING, XSD_NAMESPACE,
  268. to_zval_long, to_xml_long},
  269. {XSD_UNSIGNEDLONG, XSD_UNSIGNEDLONG_STRING, XSD_NAMESPACE,
  270. to_zval_long, to_xml_long},
  271. {XSD_INTEGER, XSD_INTEGER_STRING, XSD_NAMESPACE,
  272. to_zval_long, to_xml_long},
  273. {XSD_ANYTYPE, XSD_ANYTYPE_STRING, XSD_NAMESPACE,
  274. guess_zval_convert, guess_xml_convert},
  275. {XSD_UR_TYPE, XSD_UR_TYPE_STRING, XSD_NAMESPACE,
  276. guess_zval_convert, guess_xml_convert},
  277. {XSD_ANYURI, XSD_ANYURI_STRING, XSD_NAMESPACE,
  278. to_zval_stringc, to_xml_string},
  279. {XSD_QNAME, XSD_QNAME_STRING, XSD_NAMESPACE,
  280. to_zval_stringc, to_xml_string},
  281. {XSD_NOTATION, XSD_NOTATION_STRING, XSD_NAMESPACE,
  282. to_zval_stringc, to_xml_string},
  283. {XSD_NORMALIZEDSTRING, XSD_NORMALIZEDSTRING_STRING, XSD_NAMESPACE,
  284. to_zval_stringr, to_xml_string},
  285. {XSD_TOKEN, XSD_TOKEN_STRING, XSD_NAMESPACE,
  286. to_zval_stringc, to_xml_string},
  287. {XSD_LANGUAGE, XSD_LANGUAGE_STRING, XSD_NAMESPACE,
  288. to_zval_stringc, to_xml_string},
  289. {XSD_NMTOKEN, XSD_NMTOKEN_STRING, XSD_NAMESPACE,
  290. to_zval_stringc, to_xml_string},
  291. {XSD_NMTOKENS, XSD_NMTOKENS_STRING, XSD_NAMESPACE,
  292. to_zval_stringc, to_xml_list1},
  293. {XSD_NAME, XSD_NAME_STRING, XSD_NAMESPACE,
  294. to_zval_stringc, to_xml_string},
  295. {XSD_NCNAME, XSD_NCNAME_STRING, XSD_NAMESPACE,
  296. to_zval_stringc, to_xml_string},
  297. {XSD_ID, XSD_ID_STRING, XSD_NAMESPACE,
  298. to_zval_stringc, to_xml_string},
  299. {XSD_IDREF, XSD_IDREF_STRING, XSD_NAMESPACE,
  300. to_zval_stringc, to_xml_string},
  301. {XSD_IDREFS, XSD_IDREFS_STRING, XSD_NAMESPACE,
  302. to_zval_stringc, to_xml_list1},
  303. {XSD_ENTITY, XSD_ENTITY_STRING, XSD_NAMESPACE,
  304. to_zval_stringc, to_xml_string},
  305. {XSD_ENTITIES, XSD_ENTITIES_STRING, XSD_NAMESPACE,
  306. to_zval_stringc, to_xml_list1},
  307. {APACHE_MAP, APACHE_MAP_STRING, APACHE_NAMESPACE,
  308. to_zval_map, to_xml_map},
  309. {SOAP_ENC_OBJECT, SOAP_ENC_OBJECT_STRING, SOAP_1_1_ENC_NAMESPACE,
  310. to_zval_object, to_xml_object},
  311. {SOAP_ENC_ARRAY, SOAP_ENC_ARRAY_STRING, SOAP_1_1_ENC_NAMESPACE,
  312. to_zval_array, to_xml_array},
  313. {SOAP_ENC_ARRAY_DT, SOAP_ENC_ARRAY_DT_STRING, SOAP_1_1_ENC_NAMESPACE,
  314. to_zval_array, guess_array_map},
  315. {SOAP_ENC_OBJECT, SOAP_ENC_OBJECT_STRING, SOAP_1_2_ENC_NAMESPACE,
  316. to_zval_object, to_xml_object},
  317. {SOAP_ENC_ARRAY, SOAP_ENC_ARRAY_STRING, SOAP_1_2_ENC_NAMESPACE,
  318. to_zval_array, to_xml_array},
  319. {SOAP_ENC_ARRAY_DT, SOAP_ENC_ARRAY_DT_STRING, SOAP_1_2_ENC_NAMESPACE,
  320. to_zval_array, guess_array_map},
  321. {SOAP_ENC_INT_DT, SOAP_ENC_INT_DT_STRING, XSD_NAMESPACE,
  322. to_zval_long, to_xml_long},
  323. {SOAP_ENC_DOUBLE_DT, SOAP_ENC_DOUBLE_DT_STRING, XSD_NAMESPACE,
  324. to_zval_double, to_xml_double},
  325. /* support some of the 1999 data types */
  326. {XSD_STRING, XSD_STRING_STRING, XSD_1999_NAMESPACE,
  327. to_zval_string, to_xml_string},
  328. {XSD_BOOLEAN, XSD_BOOLEAN_STRING, XSD_1999_NAMESPACE,
  329. to_zval_bool, to_xml_bool},
  330. {XSD_DECIMAL, XSD_DECIMAL_STRING, XSD_1999_NAMESPACE,
  331. to_zval_stringc, to_xml_string},
  332. {XSD_FLOAT, XSD_FLOAT_STRING, XSD_1999_NAMESPACE,
  333. to_zval_double, to_xml_double},
  334. {XSD_DOUBLE, XSD_DOUBLE_STRING, XSD_1999_NAMESPACE,
  335. to_zval_double, to_xml_double},
  336. {XSD_LONG, XSD_LONG_STRING, XSD_1999_NAMESPACE,
  337. to_zval_long, to_xml_long},
  338. {XSD_INT, XSD_INT_STRING, XSD_1999_NAMESPACE,
  339. to_zval_long, to_xml_long},
  340. {XSD_SHORT, XSD_SHORT_STRING, XSD_1999_NAMESPACE,
  341. to_zval_long, to_xml_long},
  342. {XSD_BYTE, XSD_BYTE_STRING, XSD_1999_NAMESPACE,
  343. to_zval_long, to_xml_long},
  344. {XSD_1999_TIMEINSTANT,XSD_1999_TIMEINSTANT_STRING,XSD_1999_NAMESPACE,
  345. to_zval_stringc, to_xml_string},
  346. {XSD_ANYXML, "<anyXML>", "<anyXML>", to_zval_any, to_xml_any},
  347. {END_KNOWN_TYPES, nullptr, nullptr, guess_zval_convert, guess_xml_convert},
  348. };
  349. ///////////////////////////////////////////////////////////////////////////////
  350. static string get_full_typename(const char *ns, const char *type) {
  351. string nscat;
  352. if (ns && *ns) {
  353. nscat = ns;
  354. nscat += ':';
  355. }
  356. if (type) {
  357. nscat += type;
  358. }
  359. return nscat;
  360. }
  361. static encodePtr get_typemap_type(const char *ns, const char *type) {
  362. USE_SOAP_GLOBAL;
  363. std::string nscat = get_full_typename(ns, type);
  364. if (SOAP_GLOBAL(typemap)) {
  365. encodeMap::const_iterator iter = SOAP_GLOBAL(typemap)->find(nscat);
  366. if (iter != SOAP_GLOBAL(typemap)->end()) {
  367. return iter->second;
  368. }
  369. }
  370. return encodePtr();
  371. }
  372. void whiteSpace_replace(xmlChar* str) {
  373. while (*str != '\0') {
  374. if (*str == '\x9' || *str == '\xA' || *str == '\xD') {
  375. *str = ' ';
  376. }
  377. str++;
  378. }
  379. }
  380. void whiteSpace_collapse(xmlChar* str) {
  381. xmlChar *pos;
  382. xmlChar old;
  383. pos = str;
  384. whiteSpace_replace(str);
  385. while (*str == ' ') {
  386. str++;
  387. }
  388. old = '\0';
  389. while (*str != '\0') {
  390. if (*str != ' ' || old != ' ') {
  391. *pos = *str;
  392. pos++;
  393. }
  394. old = *str;
  395. str++;
  396. }
  397. if (old == ' ') {
  398. --pos;
  399. }
  400. *pos = '\0';
  401. }
  402. static encodePtr find_encoder_by_type_name(sdl *sdl, const char *type) {
  403. if (sdl) {
  404. for (const auto& e : sdl->encoders) {
  405. if (strcmp(e.second->details.type_str.c_str(), type) == 0) {
  406. return e.second;
  407. }
  408. }
  409. }
  410. return encodePtr();
  411. }
  412. static bool soap_check_zval_ref(const Variant& data, xmlNodePtr node) {
  413. USE_SOAP_GLOBAL;
  414. HeapObject* hash = nullptr;
  415. if (data.isObject()) {
  416. hash = data.getObjectData();
  417. }
  418. if (hash) {
  419. auto& node_map = SOAP_GLOBAL(node_map);
  420. auto node_ptr = folly::get_default(node_map, hash);
  421. if (node_ptr) {
  422. if (node_ptr == node) {
  423. return false;
  424. }
  425. xmlNodeSetName(node, node_ptr->name);
  426. xmlSetNs(node, node_ptr->ns);
  427. xmlAttrPtr attr = node_ptr->properties;
  428. const char *id;
  429. std::string prefix;
  430. if (SOAP_GLOBAL(soap_version) == SOAP_1_1) {
  431. while (1) {
  432. attr = get_attribute(attr, "id");
  433. if (attr == nullptr || attr->ns == nullptr) {
  434. break;
  435. }
  436. attr = attr->next;
  437. }
  438. if (attr) {
  439. prefix = '#';
  440. prefix += (char*)attr->children->content;
  441. id = prefix.c_str();
  442. } else {
  443. SOAP_GLOBAL(cur_uniq_ref)++;
  444. prefix = "#ref";
  445. prefix += folly::to<string>(SOAP_GLOBAL(cur_uniq_ref));
  446. id = prefix.c_str();
  447. xmlSetProp(node_ptr, BAD_CAST("id"), BAD_CAST(id+1));
  448. }
  449. xmlSetProp(node, BAD_CAST("href"), BAD_CAST(id));
  450. } else {
  451. attr = get_attribute_ex(attr, "id", SOAP_1_2_ENC_NAMESPACE);
  452. if (attr) {
  453. prefix = '#';
  454. prefix += (char*)attr->children->content;
  455. id = prefix.c_str();
  456. } else {
  457. SOAP_GLOBAL(cur_uniq_ref)++;
  458. prefix = "#ref";
  459. prefix += folly::to<string>(SOAP_GLOBAL(cur_uniq_ref));
  460. id = prefix.c_str();
  461. set_ns_prop(node_ptr, SOAP_1_2_ENC_NAMESPACE, "id", id+1);
  462. }
  463. set_ns_prop(node, SOAP_1_2_ENC_NAMESPACE, "ref", id);
  464. }
  465. return true;
  466. }
  467. node_map.emplace(hash, node);
  468. }
  469. return false;
  470. }
  471. static bool soap_check_xml_ref(Variant& data, xmlNodePtr node) {
  472. USE_SOAP_GLOBAL;
  473. auto& ref_map = SOAP_GLOBAL(ref_map);
  474. auto const it = ref_map.find(node);
  475. if (it != ref_map.end()) {
  476. auto const& data2 = it->second;
  477. if (!data.isObject() ||
  478. !data2.isObject() ||
  479. data.getObjectData() != data2.getObjectData()) {
  480. data = data2;
  481. return true;
  482. }
  483. }
  484. return false;
  485. }
  486. static void soap_add_xml_ref(Variant& data, xmlNodePtr node) {
  487. USE_SOAP_GLOBAL;
  488. auto& ref_map = SOAP_GLOBAL(ref_map);
  489. ref_map.emplace(node, data);
  490. }
  491. static xmlNodePtr master_to_xml_int(encodePtr encode, const Variant& data, int style,
  492. xmlNodePtr parent, bool check_class_map) {
  493. USE_SOAP_GLOBAL;
  494. xmlNodePtr node = nullptr;
  495. bool add_type = false;
  496. /* Special handling of class SoapVar */
  497. if (data.isObject() && data.toObject().instanceof(SoapVar::getClass())) {
  498. auto dobj = data.toObject().get();
  499. auto enc_stype = SoapVar::getEncSType(dobj);
  500. auto enc_ns = SoapVar::getEncNS(dobj);
  501. encodePtr enc = nullptr;
  502. if (!enc_stype.isNull()) {
  503. enc = enc_ns.empty()
  504. ? get_encoder_ex(SOAP_GLOBAL(sdl), enc_stype.c_str())
  505. : get_encoder(SOAP_GLOBAL(sdl), enc_ns.c_str(), enc_stype.c_str());
  506. if (!enc && SOAP_GLOBAL(typemap)) {
  507. enc = get_typemap_type(enc_ns.c_str(), enc_stype.c_str());
  508. }
  509. }
  510. if (!enc) {
  511. auto enc_type = SoapVar::getEncType(dobj);
  512. enc = get_conversion(enc_type);
  513. }
  514. if (!enc) {
  515. enc = encode;
  516. }
  517. auto enc_value = SoapVar::getEncValue(dobj);
  518. node = master_to_xml(enc, enc_value, style, parent);
  519. if (style == SOAP_ENCODED || (SOAP_GLOBAL(sdl) && encode != enc)) {
  520. if (!enc_stype.empty()) {
  521. set_ns_and_type_ex(node, enc_ns.c_str(), enc_stype.c_str());
  522. }
  523. }
  524. auto enc_name = SoapVar::getEncName(dobj);
  525. if (!enc_name.empty()) {
  526. xmlNodeSetName(node, BAD_CAST(enc_name.c_str()));
  527. }
  528. auto enc_namens = SoapVar::getEncNameNS(dobj);
  529. if (!enc_namens.empty()) {
  530. xmlNsPtr nsp = encode_add_ns(node, enc_namens.data());
  531. xmlSetNs(node, nsp);
  532. }
  533. } else {
  534. if (check_class_map && !SOAP_GLOBAL(classmap).empty() &&
  535. data.isObject()) {
  536. auto clsname = data.toObject()->getClassName();
  537. for (ArrayIter iter(SOAP_GLOBAL(classmap)); iter; ++iter) {
  538. if (same(iter.second(), clsname)) {
  539. /* TODO: namespace isn't stored */
  540. encodePtr enc = nullptr;
  541. if (SOAP_GLOBAL(sdl)) {
  542. enc = get_encoder(SOAP_GLOBAL(sdl),
  543. SOAP_GLOBAL(sdl)->target_ns.c_str(),
  544. iter.first().toString().data());
  545. if (!enc) {
  546. enc = find_encoder_by_type_name(SOAP_GLOBAL(sdl),
  547. iter.first().toString().data());
  548. }
  549. }
  550. if (enc) {
  551. if (encode != enc && style == SOAP_LITERAL) {
  552. add_type = true;
  553. }
  554. encode = enc;
  555. }
  556. break;
  557. }
  558. }
  559. }
  560. if (encode == nullptr) {
  561. encode = get_conversion(UNKNOWN_TYPE);
  562. }
  563. if (SOAP_GLOBAL(typemap) && !encode->details.type_str.empty()) {
  564. encodePtr enc = get_typemap_type(encode->details.ns.c_str(),
  565. encode->details.type_str.c_str());
  566. if (enc) encode = enc;
  567. }
  568. if (encode->to_xml) {
  569. node = encode->to_xml(&encode->details, data, style, parent);
  570. if (add_type) {
  571. set_ns_and_type(node, &encode->details);
  572. }
  573. }
  574. }
  575. return node;
  576. }
  577. xmlNodePtr master_to_xml(encodePtr encode, const Variant& data, int style,
  578. xmlNodePtr parent) {
  579. return master_to_xml_int(encode, data, style, parent, true);
  580. }
  581. static Variant master_to_zval_int(encodePtr encode, xmlNodePtr data) {
  582. USE_SOAP_GLOBAL;
  583. Variant ret;
  584. if (SOAP_GLOBAL(typemap)) {
  585. if (!encode->details.type_str.empty()) {
  586. encodePtr enc = get_typemap_type(encode->details.ns.c_str(),
  587. encode->details.type_str.c_str());
  588. if (enc) encode = enc;
  589. } else {
  590. xmlAttrPtr type_attr = get_attribute_ex(data->properties, "type",
  591. XSI_NAMESPACE);
  592. if (type_attr) {
  593. std::string ns, cptype;
  594. parse_namespace(type_attr->children->content, cptype, ns);
  595. xmlNsPtr nsptr = xmlSearchNs(data->doc, data, NS_STRING(ns));
  596. string nscat;
  597. if (nsptr) {
  598. nscat = (char*)nsptr->href;
  599. nscat += ':';
  600. }
  601. nscat += cptype.data();
  602. encodeMap::const_iterator iter = SOAP_GLOBAL(typemap)->find(nscat);
  603. if (iter != SOAP_GLOBAL(typemap)->end()) {
  604. encode = iter->second;
  605. }
  606. }
  607. }
  608. }
  609. if (encode->to_zval) {
  610. ret = encode->to_zval(&encode->details, data);
  611. }
  612. return ret;
  613. }
  614. Variant master_to_zval(encodePtr encode, xmlNodePtr data) {
  615. USE_SOAP_GLOBAL;
  616. data = check_and_resolve_href(data);
  617. if (encode == nullptr) {
  618. encode = get_conversion(UNKNOWN_TYPE);
  619. } else {
  620. /* Use xsi:type if it is defined */
  621. xmlAttrPtr type_attr = get_attribute_ex(data->properties, "type",
  622. XSI_NAMESPACE);
  623. if (type_attr) {
  624. encodePtr enc = get_encoder_from_prefix(SOAP_GLOBAL(sdl), data,
  625. type_attr->children->content);
  626. if (enc && enc != encode) {
  627. encodePtr tmp = enc;
  628. while (tmp && tmp->details.sdl_type &&
  629. tmp->details.sdl_type->kind != XSD_TYPEKIND_COMPLEX) {
  630. if (enc == tmp->details.sdl_type->encode ||
  631. tmp == tmp->details.sdl_type->encode) {
  632. enc.reset();
  633. break;
  634. }
  635. tmp = tmp->details.sdl_type->encode;
  636. }
  637. if (enc) {
  638. encode = enc;
  639. }
  640. }
  641. }
  642. }
  643. return master_to_zval_int(encode, data);
  644. }
  645. xmlNodePtr to_xml_user(encodeType* type, const Variant& data, int style,
  646. xmlNodePtr parent) {
  647. xmlNodePtr ret = nullptr;
  648. if (type && type->map && !type->map->to_xml.isNull()) {
  649. Variant return_value = vm_call_user_func(type->map->to_xml,
  650. make_vec_array(data));
  651. if (return_value.isString()) {
  652. String sdoc = return_value.toString();
  653. xmlDocPtr doc = soap_xmlParseMemory(sdoc.data(), sdoc.size());
  654. if (doc && doc->children) {
  655. ret = xmlDocCopyNode(doc->children, parent->doc, 1);
  656. }
  657. xmlFreeDoc(doc);
  658. }
  659. }
  660. if (!ret) {
  661. ret = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  662. }
  663. xmlAddChild(parent, ret);
  664. if (style == SOAP_ENCODED) {
  665. set_ns_and_type(ret, type);
  666. }
  667. return ret;
  668. }
  669. Variant to_zval_user(encodeType* type, xmlNodePtr node) {
  670. Variant return_value;
  671. if (type && type->map && !type->map->to_zval.isNull()) {
  672. xmlNodePtr copy = xmlCopyNode(node, 1);
  673. xmlBufferPtr buf = xmlBufferCreate();
  674. xmlNodeDump(buf, nullptr, copy, 0, 0);
  675. String data((char*)xmlBufferContent(buf), CopyString);
  676. xmlBufferFree(buf);
  677. xmlFreeNode(copy);
  678. return_value = vm_call_user_func(type->map->to_zval,
  679. make_vec_array(data));
  680. }
  681. return return_value;
  682. }
  683. /* TODO: get rid of "bogus".. ither by passing in the already created xmlnode
  684. or passing in the node name */
  685. /* String encode/decode */
  686. static Variant to_zval_string(encodeType* /*type*/, xmlNodePtr data) {
  687. USE_SOAP_GLOBAL;
  688. Variant ret;
  689. FIND_XML_NULL(data, ret);
  690. if (data && data->children) {
  691. if (data->children->type == XML_TEXT_NODE &&
  692. data->children->next == nullptr) {
  693. if (SOAP_GLOBAL(encoding) != nullptr) {
  694. xmlBufferPtr in =
  695. xmlBufferCreateStatic(data->children->content,
  696. xmlStrlen(data->children->content));
  697. xmlBufferPtr out = xmlBufferCreate();
  698. int n = xmlCharEncOutFunc(SOAP_GLOBAL(encoding), out, in);
  699. if (n >= 0) {
  700. ret = String((char*)xmlBufferContent(out), CopyString);
  701. } else {
  702. ret = String((char*)data->children->content, CopyString);
  703. }
  704. xmlBufferFree(out);
  705. xmlBufferFree(in);
  706. } else {
  707. ret = String((char*)data->children->content, CopyString);
  708. }
  709. } else if (data->children->type == XML_CDATA_SECTION_NODE &&
  710. data->children->next == nullptr) {
  711. ret = String((char*)data->children->content, CopyString);
  712. } else {
  713. throw SoapException("Encoding: Violation of encoding rules");
  714. }
  715. } else {
  716. ret = empty_string_variant();
  717. }
  718. return ret;
  719. }
  720. static Variant to_zval_stringr(encodeType* /*type*/, xmlNodePtr data) {
  721. USE_SOAP_GLOBAL;
  722. Variant ret;
  723. FIND_XML_NULL(data, ret);
  724. if (data && data->children) {
  725. if (data->children->type == XML_TEXT_NODE &&
  726. data->children->next == nullptr) {
  727. whiteSpace_replace(data->children->content);
  728. if (SOAP_GLOBAL(encoding) != nullptr) {
  729. xmlBufferPtr in =
  730. xmlBufferCreateStatic(data->children->content,
  731. xmlStrlen(data->children->content));
  732. xmlBufferPtr out = xmlBufferCreate();
  733. int n = xmlCharEncOutFunc(SOAP_GLOBAL(encoding), out, in);
  734. if (n >= 0) {
  735. ret = String((char*)xmlBufferContent(out), CopyString);
  736. } else {
  737. ret = String((char*)data->children->content, CopyString);
  738. }
  739. xmlBufferFree(out);
  740. xmlBufferFree(in);
  741. } else {
  742. ret = String((char*)data->children->content, CopyString);
  743. }
  744. } else if (data->children->type == XML_CDATA_SECTION_NODE &&
  745. data->children->next == nullptr) {
  746. ret = String((char*)data->children->content, CopyString);
  747. } else {
  748. throw SoapException("Encoding: Violation of encoding rules");
  749. }
  750. } else {
  751. ret = empty_string_variant();
  752. }
  753. return ret;
  754. }
  755. static Variant to_zval_stringc(encodeType* /*type*/, xmlNodePtr data) {
  756. USE_SOAP_GLOBAL;
  757. Variant ret;
  758. FIND_XML_NULL(data, ret);
  759. if (data && data->children) {
  760. if (data->children->type == XML_TEXT_NODE &&
  761. data->children->next == nullptr) {
  762. whiteSpace_collapse(data->children->content);
  763. if (SOAP_GLOBAL(encoding) != nullptr) {
  764. xmlBufferPtr in =
  765. xmlBufferCreateStatic(data->children->content,
  766. xmlStrlen(data->children->content));
  767. xmlBufferPtr out = xmlBufferCreate();
  768. int n = xmlCharEncOutFunc(SOAP_GLOBAL(encoding), out, in);
  769. if (n >= 0) {
  770. ret = String((char*)xmlBufferContent(out), CopyString);
  771. } else {
  772. ret = String((char*)data->children->content, CopyString);
  773. }
  774. xmlBufferFree(out);
  775. xmlBufferFree(in);
  776. } else {
  777. ret = String((char*)data->children->content, CopyString);
  778. }
  779. } else if (data->children->type == XML_CDATA_SECTION_NODE &&
  780. data->children->next == nullptr) {
  781. ret = String((char*)data->children->content, CopyString);
  782. } else {
  783. throw SoapException("Encoding: Violation of encoding rules");
  784. }
  785. } else {
  786. ret = empty_string_variant();
  787. }
  788. return ret;
  789. }
  790. static Variant to_zval_base64(encodeType* /*type*/, xmlNodePtr data) {
  791. Variant ret;
  792. FIND_XML_NULL(data, ret);
  793. if (data && data->children) {
  794. if (data->children->type == XML_TEXT_NODE &&
  795. data->children->next == nullptr) {
  796. whiteSpace_collapse(data->children->content);
  797. String str =
  798. StringUtil::Base64Decode(String((const char*)data->children->content));
  799. if (str.isNull()) {
  800. throw SoapException("Encoding: Violation of encoding rules");
  801. }
  802. ret = str;
  803. } else if (data->children->type == XML_CDATA_SECTION_NODE &&
  804. data->children->next == nullptr) {
  805. String str =
  806. StringUtil::Base64Decode(String((const char*)data->children->content));
  807. if (str.isNull()) {
  808. throw SoapException("Encoding: Violation of encoding rules");
  809. }
  810. ret = str;
  811. } else {
  812. throw SoapException("Encoding: Violation of encoding rules");
  813. }
  814. } else {
  815. ret = empty_string_variant();
  816. }
  817. return ret;
  818. }
  819. static Variant to_zval_hexbin(encodeType* /*type*/, xmlNodePtr data) {
  820. Variant ret;
  821. FIND_XML_NULL(data, ret);
  822. if (data && data->children) {
  823. if (data->children->type == XML_TEXT_NODE &&
  824. data->children->next == nullptr) {
  825. whiteSpace_collapse(data->children->content);
  826. } else if (data->children->type != XML_CDATA_SECTION_NODE ||
  827. data->children->next != nullptr) {
  828. throw SoapException("Encoding: Violation of encoding rules");
  829. }
  830. auto const str =
  831. HHVM_FN(hex2bin)(String((const char*)data->children->content)).toString();
  832. if (str.isNull()) {
  833. throw SoapException("Encoding: Violation of encoding rules");
  834. }
  835. ret = str;
  836. } else {
  837. ret = empty_string_variant();
  838. }
  839. return ret;
  840. }
  841. static
  842. xmlNodePtr to_xml_string(encodeType* type, const Variant& data, int style,
  843. xmlNodePtr parent) {
  844. USE_SOAP_GLOBAL;
  845. xmlNodePtr ret = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  846. xmlAddChild(parent, ret);
  847. FIND_ZVAL_NULL(data, ret, style);
  848. String str = data.toString();
  849. if (SOAP_GLOBAL(encoding) != nullptr) {
  850. xmlBufferPtr in = xmlBufferCreateStatic((void*)str.data(), str.size());
  851. xmlBufferPtr out = xmlBufferCreate();
  852. int n = xmlCharEncInFunc(SOAP_GLOBAL(encoding), out, in);
  853. if (n >= 0) {
  854. str = String((char*)xmlBufferContent(out), n, CopyString);
  855. }
  856. xmlBufferFree(out);
  857. xmlBufferFree(in);
  858. }
  859. if (!php_libxml_xmlCheckUTF8(BAD_CAST(str.data()))) {
  860. char *err = (char*)req::malloc_noptrs(str.size() + 8);
  861. char c;
  862. memcpy(err, str.data(), str.size() + 1);
  863. int i = 0;
  864. while ((c = err[i++])) {
  865. if ((c & 0x80) == 0) {
  866. } else if ((c & 0xe0) == 0xc0) {
  867. if ((err[i] & 0xc0) != 0x80) {
  868. break;
  869. }
  870. i++;
  871. } else if ((c & 0xf0) == 0xe0) {
  872. if ((err[i] & 0xc0) != 0x80 || (err[i+1] & 0xc0) != 0x80) {
  873. break;
  874. }
  875. i += 2;
  876. } else if ((c & 0xf8) == 0xf0) {
  877. if ((err[i] & 0xc0) != 0x80 ||
  878. (err[i+1] & 0xc0) != 0x80 || (err[i+2] & 0xc0) != 0x80) {
  879. break;
  880. }
  881. i += 3;
  882. } else {
  883. break;
  884. }
  885. }
  886. if (c) {
  887. err[i-1] = '\\';
  888. err[i++] = 'x';
  889. err[i++] = ((unsigned char)c >> 4) +
  890. ((((unsigned char)c >> 4) > 9) ? ('a' - 10) : '0');
  891. err[i++] = (c & 15) + (((c & 15) > 9) ? ('a' - 10) : '0');
  892. err[i++] = '.';
  893. err[i++] = '.';
  894. err[i++] = '.';
  895. err[i++] = 0;
  896. }
  897. std::string serr = err;
  898. req::free(err);
  899. throw SoapException("Encoding: string '%s' is not a valid utf-8 string",
  900. serr.c_str());
  901. }
  902. xmlNodePtr text = xmlNewTextLen(BAD_CAST(str.data()), str.size());
  903. xmlAddChild(ret, text);
  904. if (style == SOAP_ENCODED) {
  905. set_ns_and_type(ret, type);
  906. }
  907. return ret;
  908. }
  909. static
  910. xmlNodePtr to_xml_base64(encodeType* type, const Variant& data, int style,
  911. xmlNodePtr parent) {
  912. xmlNodePtr ret = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  913. xmlAddChild(parent, ret);
  914. FIND_ZVAL_NULL(data, ret, style);
  915. String str = StringUtil::Base64Encode(data.toString());
  916. xmlAddChild(ret, xmlNewTextLen(BAD_CAST(str.data()), str.size()));
  917. if (style == SOAP_ENCODED) {
  918. set_ns_and_type(ret, type);
  919. }
  920. return ret;
  921. }
  922. static
  923. xmlNodePtr to_xml_hexbin(encodeType* type, const Variant& data, int style,
  924. xmlNodePtr parent) {
  925. xmlNodePtr ret = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  926. xmlAddChild(parent, ret);
  927. FIND_ZVAL_NULL(data, ret, style);
  928. String str = HHVM_FN(bin2hex)(data.toString());
  929. xmlAddChild(ret, xmlNewTextLen(BAD_CAST(str.data()), str.size()));
  930. if (style == SOAP_ENCODED) {
  931. set_ns_and_type(ret, type);
  932. }
  933. return ret;
  934. }
  935. static Variant to_zval_double(encodeType* /*type*/, xmlNodePtr data) {
  936. Variant ret;
  937. FIND_XML_NULL(data, ret);
  938. if (data && data->children) {
  939. if (data->children->type == XML_TEXT_NODE &&
  940. data->children->next == nullptr) {
  941. int64_t lval; double dval;
  942. whiteSpace_collapse(data->children->content);
  943. String content((char*)data->children->content, CopyString);
  944. auto dt = is_numeric_string((const char *)data->children->content,
  945. data->children->content ?
  946. strlen((char*)data->children->content) : 0,
  947. &lval, &dval, 0);
  948. if (isIntType(dt)) {
  949. ret = lval;
  950. } else if (isDoubleType(dt)) {
  951. ret = dval;
  952. } else {
  953. if (data->children->content) {
  954. if (strcasecmp((const char *)data->children->content, "NaN") == 0) {
  955. ret = atof("nan");
  956. } else if (strcasecmp((const char *)data->children->content, "INF")
  957. == 0) {
  958. ret = atof("inf");
  959. } else if (strcasecmp((const char *)data->children->content, "-INF")
  960. == 0) {
  961. ret = -atof("inf");
  962. } else {
  963. throw SoapException("Encoding: Violation of encoding rules");
  964. }
  965. } else {
  966. throw SoapException("Encoding: Violation of encoding rules");
  967. }
  968. }
  969. } else {
  970. throw SoapException("Encoding: Violation of encoding rules");
  971. }
  972. }
  973. return ret;
  974. }
  975. static Variant to_zval_long(encodeType* /*type*/, xmlNodePtr data) {
  976. Variant ret;
  977. FIND_XML_NULL(data, ret);
  978. if (data && data->children) {
  979. if (data->children->type == XML_TEXT_NODE &&
  980. data->children->next == nullptr) {
  981. int64_t lval; double dval;
  982. whiteSpace_collapse(data->children->content);
  983. auto dt = is_numeric_string((const char *)data->children->content,
  984. data->children->content ?
  985. strlen((char*)data->children->content) : 0,
  986. &lval, &dval, 0);
  987. if (isIntType(dt)) {
  988. ret = (int64_t)lval;
  989. } else if (isDoubleType(dt)) {
  990. ret = dval;
  991. } else {
  992. throw SoapException("Encoding: Violation of encoding rules");
  993. }
  994. } else {
  995. throw SoapException("Encoding: Violation of encoding rules");
  996. }
  997. }
  998. return ret;
  999. }
  1000. static xmlNodePtr to_xml_long(encodeType* type, const Variant& data, int style,
  1001. xmlNodePtr parent) {
  1002. xmlNodePtr ret = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1003. xmlAddChild(parent, ret);
  1004. FIND_ZVAL_NULL(data, ret, style);
  1005. if (data.isDouble()) {
  1006. char s[256];
  1007. snprintf(s, sizeof(s), "%0.0F", floor(data.toDouble()));
  1008. xmlNodeSetContent(ret, BAD_CAST(s));
  1009. } else {
  1010. Variant d = data.toInt64();
  1011. String sd = d.toString();
  1012. xmlNodeSetContentLen(ret, BAD_CAST(sd.data()), sd.size());
  1013. }
  1014. if (style == SOAP_ENCODED) {
  1015. set_ns_and_type(ret, type);
  1016. }
  1017. return ret;
  1018. }
  1019. static
  1020. xmlNodePtr to_xml_double(encodeType* type, const Variant& data, int style,
  1021. xmlNodePtr parent) {
  1022. xmlNodePtr ret = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1023. xmlAddChild(parent, ret);
  1024. FIND_ZVAL_NULL(data, ret, style);
  1025. Variant d = data.toDouble();
  1026. String sd = d.toString();
  1027. xmlNodeSetContentLen(ret, BAD_CAST(sd.data()), sd.size());
  1028. if (style == SOAP_ENCODED) {
  1029. set_ns_and_type(ret, type);
  1030. }
  1031. return ret;
  1032. }
  1033. static Variant to_zval_bool(encodeType* /*type*/, xmlNodePtr data) {
  1034. Variant ret;
  1035. FIND_XML_NULL(data, ret);
  1036. if (data && data->children) {
  1037. if (data->children->type == XML_TEXT_NODE &&
  1038. data->children->next == nullptr) {
  1039. whiteSpace_collapse(data->children->content);
  1040. const char *content = (const char *)data->children->content;
  1041. if (strcasecmp((char*)content, "true") == 0 ||
  1042. strcasecmp((char*)content, "t") == 0 ||
  1043. strcmp((char*)content, "1") == 0) {
  1044. ret = true;
  1045. } else if (strcasecmp((char*)content, "false") == 0 ||
  1046. strcasecmp((char*)content, "f") == 0 ||
  1047. strcmp((char*)content, "0") == 0) {
  1048. ret = false;
  1049. } else {
  1050. ret = String((char*)content, CopyString).toBoolean();
  1051. }
  1052. } else {
  1053. throw SoapException("Encoding: Violation of encoding rules");
  1054. }
  1055. }
  1056. return ret;
  1057. }
  1058. static xmlNodePtr to_xml_bool(encodeType* type, const Variant& data, int style,
  1059. xmlNodePtr parent) {
  1060. xmlNodePtr ret = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1061. xmlAddChild(parent, ret);
  1062. FIND_ZVAL_NULL(data, ret, style);
  1063. if (data.toBoolean()) {
  1064. xmlNodeSetContent(ret, BAD_CAST("true"));
  1065. } else {
  1066. xmlNodeSetContent(ret, BAD_CAST("false"));
  1067. }
  1068. if (style == SOAP_ENCODED) {
  1069. set_ns_and_type(ret, type);
  1070. }
  1071. return ret;
  1072. }
  1073. /* Null encode/decode */
  1074. static Variant to_zval_null(encodeType* /*type*/, xmlNodePtr /*data*/) {
  1075. return init_null();
  1076. }
  1077. static xmlNodePtr to_xml_null(encodeType* /*type*/, const Variant& /*data*/,
  1078. int style, xmlNodePtr parent) {
  1079. xmlNodePtr ret = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1080. xmlAddChild(parent, ret);
  1081. if (style == SOAP_ENCODED) {
  1082. set_xsi_nil(ret);
  1083. }
  1084. return ret;
  1085. }
  1086. namespace {
  1087. // Returns Uninit for a missing property. May also return Uninit for properties
  1088. // on objects that haven't yet been initialized.
  1089. TypedValue get_property(const Variant &object, const char* name) {
  1090. String sname(name);
  1091. if (object.isObject()) {
  1092. auto const obj = object.toObject();
  1093. auto const lval = obj->getPropIgnoreAccessibility(sname.get());
  1094. return lval ? lval.tv() : make_tv<KindOfUninit>();
  1095. } else if (object.isArray()) {
  1096. return object.asCArrRef()->get(sname.get());
  1097. }
  1098. return make_tv<KindOfUninit>();
  1099. }
  1100. }
  1101. const StaticString
  1102. s_any("any"),
  1103. s__("_");
  1104. static void model_to_zval_any(Variant &ret, xmlNodePtr node) {
  1105. const char* name = nullptr;
  1106. Variant any;
  1107. while (node != nullptr) {
  1108. auto const prop = get_property(ret, (const char *)node->name);
  1109. if (type(prop) == KindOfUninit) {
  1110. Variant val = master_to_zval(get_conversion(XSD_ANYXML), node);
  1111. if (!any.isNull() && !any.isArray()) {
  1112. Array arr = Array::Create();
  1113. if (name) {
  1114. arr.set(String(name, CopyString), any);
  1115. } else {
  1116. arr.append(any);
  1117. }
  1118. any = arr;
  1119. }
  1120. if (val.isString() && val.toString().charAt(0) == '<') {
  1121. name = nullptr;
  1122. while (node->next != nullptr) {
  1123. Variant val2 = master_to_zval(get_conversion(XSD_ANYXML),
  1124. node->next);
  1125. if (!val2.isString()) {
  1126. break;
  1127. }
  1128. concat_assign(val.asTypedValue(), val2.toString());
  1129. node = node->next;
  1130. }
  1131. } else {
  1132. name = (const char*)node->name;
  1133. }
  1134. if (any.isNull()) {
  1135. if (name) {
  1136. Array arr = Array::Create();
  1137. arr.set(String(name, CopyString), val);
  1138. any = arr;
  1139. name = nullptr;
  1140. } else {
  1141. any = val;
  1142. }
  1143. } else {
  1144. /* Add array element */
  1145. if (name) {
  1146. String name_str(name);
  1147. if (any.asArrRef().exists(name_str)) {
  1148. auto const el = any.asArrRef().lval(name_str);
  1149. if (!isArrayLikeType(el.type())) {
  1150. /* Convert into array */
  1151. Array arr = Array::Create();
  1152. arr.append(el.tv());
  1153. tvSet(make_array_like_tv(arr.get()), el);
  1154. }
  1155. asArrRef(el).append(val);
  1156. } else {
  1157. any.asArrRef().set(name_str, val);
  1158. }
  1159. } else {
  1160. any.asArrRef().append(val);
  1161. }
  1162. name = nullptr;
  1163. }
  1164. }
  1165. node = node->next;
  1166. }
  1167. if (any.toBoolean()) {
  1168. if (name) {
  1169. ret.toObject()->o_set(String(name), any);
  1170. } else {
  1171. ret.toObject()->setProp(nullptr, s_any.get(), *any.asTypedValue());
  1172. }
  1173. }
  1174. }
  1175. static void model_to_zval_object(Variant &ret, sdlContentModelPtr model,
  1176. xmlNodePtr data, sdl *sdl) {
  1177. USE_SOAP_GLOBAL;
  1178. switch (model->kind) {
  1179. case XSD_CONTENT_ELEMENT:
  1180. if (!model->u_element->name.empty()) {
  1181. xmlNodePtr node = get_node(data->children,
  1182. (char*)model->u_element->name.c_str());
  1183. if (node) {
  1184. Variant val;
  1185. xmlNodePtr r_node = check_and_resolve_href(node);
  1186. if (r_node && r_node->children && r_node->children->content) {
  1187. if (!model->u_element->fixed.empty() &&
  1188. model->u_element->fixed != (char*)r_node->children->content) {
  1189. throw SoapException("Encoding: Element '%s' has fixed value '%s' "
  1190. "(value '%s' is not allowed)",
  1191. model->u_element->name.c_str(),
  1192. model->u_element->fixed.c_str(),
  1193. r_node->children->content);
  1194. }
  1195. val = master_to_zval(model->u_element->encode, r_node);
  1196. } else if (!model->u_element->fixed.empty()) {
  1197. xmlNodePtr dummy = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1198. xmlNodeSetContent(dummy, BAD_CAST(model->u_element->fixed.c_str()));
  1199. val = master_to_zval(model->u_element->encode, dummy);
  1200. xmlFreeNode(dummy);
  1201. } else if (!model->u_element->def.empty() &&
  1202. !model->u_element->nillable) {
  1203. xmlNodePtr dummy = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1204. xmlNodeSetContent(dummy,
  1205. BAD_CAST(model->u_element->def.c_str()));
  1206. val = master_to_zval(model->u_element->encode, dummy);
  1207. xmlFreeNode(dummy);
  1208. } else {
  1209. val = master_to_zval(model->u_element->encode, r_node);
  1210. }
  1211. if ((node = get_node(node->next,
  1212. (char*)model->u_element->name.c_str())) != nullptr) {
  1213. Array array = Array::Create();
  1214. array.append(val);
  1215. do {
  1216. if (node && node->children && node->children->content) {
  1217. if (!model->u_element->fixed.empty() &&
  1218. model->u_element->fixed != (char*)node->children->content) {
  1219. throw SoapException("Encoding: Element '%s' has fixed value "
  1220. "'%s' (value '%s' is not allowed)",
  1221. model->u_element->name.c_str(),
  1222. model->u_element->fixed.c_str(),
  1223. node->children->content);
  1224. }
  1225. val = master_to_zval(model->u_element->encode, node);
  1226. } else if (!model->u_element->fixed.empty()) {
  1227. xmlNodePtr dummy = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1228. xmlNodeSetContent(dummy,
  1229. BAD_CAST(model->u_element->fixed.c_str()));
  1230. val = master_to_zval(model->u_element->encode, dummy);
  1231. xmlFreeNode(dummy);
  1232. } else if (!model->u_element->def.empty() &&
  1233. !model->u_element->nillable) {
  1234. xmlNodePtr dummy = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1235. xmlNodeSetContent(dummy,
  1236. BAD_CAST(model->u_element->def.c_str()));
  1237. val = master_to_zval(model->u_element->encode, dummy);
  1238. xmlFreeNode(dummy);
  1239. } else {
  1240. val = master_to_zval(model->u_element->encode, node);
  1241. }
  1242. array.append(val);
  1243. } while ((node = get_node
  1244. (node->next,
  1245. (char*)model->u_element->name.c_str())) != nullptr);
  1246. val = array;
  1247. } else if ((!val.isNull() || !model->u_element->nillable) &&
  1248. (SOAP_GLOBAL(features) & SOAP_SINGLE_ELEMENT_ARRAYS) &&
  1249. (model->max_occurs == -1 || model->max_occurs > 1)) {
  1250. Array array = Array::Create();
  1251. array.append(val);
  1252. val = array;
  1253. }
  1254. ret.toObject()->o_set(String(model->u_element->name), val);
  1255. }
  1256. }
  1257. break;
  1258. case XSD_CONTENT_ALL:
  1259. case XSD_CONTENT_SEQUENCE:
  1260. case XSD_CONTENT_CHOICE: {
  1261. sdlContentModelPtr any;
  1262. for (unsigned int i = 0; i < model->u_content.size(); i++) {
  1263. sdlContentModelPtr content = model->u_content[i];
  1264. if (content->kind == XSD_CONTENT_ANY) {
  1265. any = content;
  1266. } else {
  1267. model_to_zval_object(ret, content, data, sdl);
  1268. }
  1269. }
  1270. if (any) {
  1271. model_to_zval_any(ret, data->children);
  1272. }
  1273. break;
  1274. }
  1275. case XSD_CONTENT_GROUP:
  1276. model_to_zval_object(ret, model->u_group->model, data, sdl);
  1277. break;
  1278. default:
  1279. break;
  1280. }
  1281. }
  1282. /* Struct encode/decode */
  1283. static Variant to_zval_object_ex(encodeType* etype, xmlNodePtr data,
  1284. const char *pce) {
  1285. USE_SOAP_GLOBAL;
  1286. const char *ce = "stdClass";
  1287. String clsname;
  1288. if (pce) {
  1289. ce = pce;
  1290. } else if (!SOAP_GLOBAL(classmap).empty() && !etype->type_str.empty()) {
  1291. String type_str(etype->type_str);
  1292. if (SOAP_GLOBAL(classmap).exists(type_str)) {
  1293. clsname = SOAP_GLOBAL(classmap)[type_str].toString();
  1294. ce = clsname.data();
  1295. }
  1296. }
  1297. Variant ret;
  1298. bool redo_any = false;
  1299. sdlType *sdlType = etype->sdl_type;
  1300. sdl *sdl = SOAP_GLOBAL(sdl);
  1301. if (sdlType) {
  1302. if (sdlType->kind == XSD_TYPEKIND_RESTRICTION &&
  1303. sdlType->encode && etype != &sdlType->encode->details) {
  1304. encodePtr enc = sdlType->encode;
  1305. while (enc && enc->details.sdl_type &&
  1306. enc->details.sdl_type->kind != XSD_TYPEKIND_SIMPLE &&
  1307. enc->details.sdl_type->kind != XSD_TYPEKIND_LIST &&
  1308. enc->details.sdl_type->kind != XSD_TYPEKIND_UNION) {
  1309. enc = enc->details.sdl_type->encode;
  1310. }
  1311. if (enc) {
  1312. if (soap_check_xml_ref(ret, data)) {
  1313. return ret;
  1314. }
  1315. ret = create_object(ce, Array());
  1316. ret.toObject()->setProp(nullptr, s__.get(),
  1317. *master_to_zval_int(enc, data).asTypedValue());
  1318. } else {
  1319. FIND_XML_NULL(data, ret);
  1320. if (soap_check_xml_ref(ret, data)) {
  1321. return ret;
  1322. }
  1323. ret = create_object(ce, Array());
  1324. soap_add_xml_ref(ret, data);
  1325. }
  1326. } else if (sdlType->kind == XSD_TYPEKIND_EXTENSION &&
  1327. sdlType->encode &&
  1328. etype != &sdlType->encode->details) {
  1329. encodeType &details = sdlType->encode->details;
  1330. if (de

Large files files are truncated, but you can click here to view the full file