PageRenderTime 68ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/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
  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 (details.sdl_type &&
  1331. details.sdl_type->kind != XSD_TYPEKIND_SIMPLE &&
  1332. details.sdl_type->kind != XSD_TYPEKIND_LIST &&
  1333. details.sdl_type->kind != XSD_TYPEKIND_UNION) {
  1334. CHECK_XML_NULL(data)
  1335. if (soap_check_xml_ref(ret, data)) {
  1336. return ret;
  1337. }
  1338. if (strcasecmp(ce, "stdClass") != 0 &&
  1339. sdlType->encode->to_zval == sdl_guess_convert_zval &&
  1340. details.sdl_type != nullptr &&
  1341. (details.sdl_type->kind == XSD_TYPEKIND_COMPLEX ||
  1342. details.sdl_type->kind == XSD_TYPEKIND_RESTRICTION ||
  1343. details.sdl_type->kind == XSD_TYPEKIND_EXTENSION) &&
  1344. (details.sdl_type->encode == nullptr ||
  1345. !isSoapArrayType(details.sdl_type->encode->details.type))) {
  1346. ret = to_zval_object_ex(&sdlType->encode->details, data, ce);
  1347. } else {
  1348. ret = master_to_zval_int(sdlType->encode, data);
  1349. }
  1350. soap_add_xml_ref(ret, data);
  1351. redo_any = type(get_property(ret, "any")) != KindOfUninit;
  1352. } else {
  1353. if (soap_check_xml_ref(ret, data)) {
  1354. return ret;
  1355. }
  1356. ret = create_object(ce, Array());
  1357. soap_add_xml_ref(ret, data);
  1358. ret.toObject()->setProp(
  1359. nullptr,
  1360. s__.get(),
  1361. *master_to_zval_int(sdlType->encode, data).asTypedValue()
  1362. );
  1363. }
  1364. } else {
  1365. FIND_XML_NULL(data, ret);
  1366. if (soap_check_xml_ref(ret, data)) {
  1367. return ret;
  1368. }
  1369. ret = create_object(ce, Array());
  1370. soap_add_xml_ref(ret, data);
  1371. }
  1372. if (sdlType->model) {
  1373. if (redo_any) {
  1374. ret.toObject()->unsetProp(nullptr, s_any.get());
  1375. soap_add_xml_ref(ret, data);
  1376. }
  1377. model_to_zval_object(ret, sdlType->model, data, sdl);
  1378. if (redo_any) {
  1379. model_to_zval_any(ret, data->children);
  1380. }
  1381. }
  1382. if (!sdlType->attributes.empty()) {
  1383. for (sdlAttributeMap::const_iterator iter = sdlType->attributes.begin();
  1384. iter != sdlType->attributes.end(); ++iter) {
  1385. sdlAttributePtr attr = iter->second;
  1386. if (!attr->name.empty()) {
  1387. xmlAttrPtr val = get_attribute(data->properties,
  1388. (char*)attr->name.c_str());
  1389. const char *str_val = nullptr;
  1390. if (val && val->children && val->children->content) {
  1391. str_val = (char*)val->children->content;
  1392. if (!attr->fixed.empty() && attr->fixed != str_val) {
  1393. throw SoapException("Encoding: Attribute '%s' has fixed value"
  1394. " '%s' (value '%s' is not allowed)",
  1395. attr->name.c_str(), attr->fixed.c_str(),
  1396. str_val);
  1397. }
  1398. } else if (!attr->fixed.empty()) {
  1399. str_val = attr->fixed.c_str();
  1400. } else if (!attr->def.empty()) {
  1401. str_val = attr->def.c_str();
  1402. }
  1403. if (str_val) {
  1404. xmlNodePtr dummy = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1405. xmlNodePtr text = xmlNewText(BAD_CAST(str_val));
  1406. xmlAddChild(dummy, text);
  1407. Variant data = master_to_zval(attr->encode, dummy);
  1408. xmlFreeNode(dummy);
  1409. ret.toObject()->o_set(String(attr->name), data);
  1410. }
  1411. }
  1412. }
  1413. }
  1414. } else {
  1415. FIND_XML_NULL(data, ret);
  1416. if (soap_check_xml_ref(ret, data)) {
  1417. return ret;
  1418. }
  1419. ret = create_object(ce, Array());
  1420. soap_add_xml_ref(ret, data);
  1421. xmlNodePtr trav = data->children;
  1422. auto obj = ret.asObjRef();
  1423. while (trav != nullptr) {
  1424. if (trav->type == XML_ELEMENT_NODE) {
  1425. Variant tmpVal = master_to_zval(encodePtr(), trav);
  1426. auto const propName = (char*)trav->name;
  1427. // $prop = $ret->{$propName}
  1428. auto const name = String(propName, CopyString);
  1429. auto const prop = obj->getPropIgnoreAccessibility(name.get());
  1430. if (!prop.is_set() || prop.type() == KindOfUninit) {
  1431. if (!trav->next || !get_node(trav->next, propName)) {
  1432. obj->o_set(name, tmpVal);
  1433. } else {
  1434. VArrayInit arr{1};
  1435. arr.append(tmpVal);
  1436. obj->o_set(name, arr.toArray());
  1437. }
  1438. } else {
  1439. if (!isArrayType(prop.type())) {
  1440. /* Convert into array */
  1441. VArrayInit arr{2};
  1442. arr.append(prop.tv());
  1443. arr.append(tmpVal);
  1444. obj->o_set(name, arr.toArray());
  1445. } else {
  1446. asArrRef(prop).append(tmpVal);
  1447. }
  1448. }
  1449. }
  1450. trav = trav->next;
  1451. }
  1452. }
  1453. return ret;
  1454. }
  1455. static Variant to_zval_object(encodeType* type, xmlNodePtr data) {
  1456. return to_zval_object_ex(type, data, nullptr);
  1457. }
  1458. static int model_to_xml_object(xmlNodePtr node, sdlContentModelPtr model,
  1459. Variant &object, int style, int strict) {
  1460. switch (model->kind) {
  1461. case XSD_CONTENT_ELEMENT: {
  1462. xmlNodePtr property;
  1463. encodePtr enc;
  1464. auto const data = get_property(object, model->u_element->name.c_str());
  1465. if (type(data) != KindOfUninit) {
  1466. if (type(data) == KindOfNull &&
  1467. !model->u_element->nillable && model->min_occurs > 0 && !strict) {
  1468. return 0;
  1469. }
  1470. enc = model->u_element->encode;
  1471. if ((model->max_occurs == -1 || model->max_occurs > 1) &&
  1472. isArrayType(type(data)) &&
  1473. val(data).parr->isVectorData()) {
  1474. for (ArrayIter iter(val(data).parr); iter; ++iter) {
  1475. Variant val = iter.second();
  1476. if (val.isNull() && model->u_element->nillable) {
  1477. property = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1478. xmlAddChild(node, property);
  1479. set_xsi_nil(property);
  1480. } else {
  1481. property = master_to_xml(enc, val, style, node);
  1482. if (property->children && property->children->content &&
  1483. !model->u_element->fixed.empty() &&
  1484. model->u_element->fixed != (char*)property->children->content) {
  1485. throw SoapException("Encoding: Element '%s' has fixed value "
  1486. "'%s' (value '%s' is not allowed)",
  1487. model->u_element->name.c_str(),
  1488. model->u_element->fixed.c_str(),
  1489. property->children->content);
  1490. }
  1491. }
  1492. xmlNodeSetName(property, BAD_CAST(model->u_element->name.c_str()));
  1493. if (style == SOAP_LITERAL &&
  1494. !model->u_element->namens.empty() &&
  1495. model->u_element->form == XSD_FORM_QUALIFIED) {
  1496. xmlNsPtr nsp = encode_add_ns(property,
  1497. model->u_element->namens.c_str());
  1498. xmlSetNs(property, nsp);
  1499. }
  1500. }
  1501. } else {
  1502. if (type(data) == KindOfNull && model->u_element->nillable) {
  1503. property = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1504. xmlAddChild(node, property);
  1505. set_xsi_nil(property);
  1506. } else if (type(data) == KindOfNull && model->min_occurs == 0) {
  1507. return 1;
  1508. } else {
  1509. property = master_to_xml(enc, tvAsCVarRef(data), style, node);
  1510. if (property->children && property->children->content &&
  1511. !model->u_element->fixed.empty() &&
  1512. model->u_element->fixed != (char*)property->children->content) {
  1513. throw SoapException("Encoding: Element '%s' has fixed value '%s' "
  1514. "(value '%s' is not allowed)",
  1515. model->u_element->name.c_str(),
  1516. model->u_element->fixed.c_str(),
  1517. property->children->content);
  1518. }
  1519. }
  1520. xmlNodeSetName(property, BAD_CAST(model->u_element->name.c_str()));
  1521. if (style == SOAP_LITERAL &&
  1522. !model->u_element->namens.empty() &&
  1523. model->u_element->form == XSD_FORM_QUALIFIED) {
  1524. xmlNsPtr nsp = encode_add_ns(property,
  1525. model->u_element->namens.c_str());
  1526. xmlSetNs(property, nsp);
  1527. }
  1528. }
  1529. return 1;
  1530. } else if (strict && model->u_element->nillable && model->min_occurs > 0) {
  1531. property = xmlNewNode(nullptr, BAD_CAST(model->u_element->name.c_str()));
  1532. xmlAddChild(node, property);
  1533. set_xsi_nil(property);
  1534. if (style == SOAP_LITERAL &&
  1535. model->u_element->form == XSD_FORM_QUALIFIED) {
  1536. xmlNsPtr nsp = encode_add_ns(property,
  1537. model->u_element->namens.c_str());
  1538. xmlSetNs(property, nsp);
  1539. }
  1540. return 1;
  1541. } else if (model->min_occurs == 0) {
  1542. return 2;
  1543. } else {
  1544. if (strict) {
  1545. throw SoapException("Encoding: object hasn't '%s' property",
  1546. model->u_element->name.c_str());
  1547. }
  1548. return 0;
  1549. }
  1550. break;
  1551. }
  1552. case XSD_CONTENT_ANY: {
  1553. encodePtr enc;
  1554. auto const data = get_property(object, "any");
  1555. if (type(data) != KindOfUninit) {
  1556. enc = get_conversion(XSD_ANYXML);
  1557. if ((model->max_occurs == -1 || model->max_occurs > 1) &&
  1558. isArrayType(type(data)) &&
  1559. val(data).parr->isVectorData()) {
  1560. for (ArrayIter iter(val(data).parr); iter; ++iter) {
  1561. master_to_xml(enc, iter.second(), style, node);
  1562. }
  1563. } else {
  1564. master_to_xml(enc, tvAsCVarRef(data), style, node);
  1565. }
  1566. return 1;
  1567. } else if (model->min_occurs == 0) {
  1568. return 2;
  1569. } else {
  1570. if (strict) {
  1571. throw SoapException( "Encoding: object hasn't 'any' property");
  1572. }
  1573. return 0;
  1574. }
  1575. break;
  1576. }
  1577. case XSD_CONTENT_SEQUENCE:
  1578. case XSD_CONTENT_ALL:
  1579. for (unsigned int i = 0; i < model->u_content.size(); i++) {
  1580. sdlContentModelPtr tmp = model->u_content[i];
  1581. if (!model_to_xml_object(node,tmp,object,style,tmp->min_occurs > 0) &&
  1582. tmp->min_occurs > 0) {
  1583. return 0;
  1584. }
  1585. }
  1586. return 1;
  1587. case XSD_CONTENT_CHOICE: {
  1588. int ret = 0;
  1589. for (unsigned int i = 0; i < model->u_content.size(); i++) {
  1590. sdlContentModelPtr tmp = model->u_content[i];
  1591. int tmp_ret = model_to_xml_object(node, tmp, object, style, 0);
  1592. if (tmp_ret == 1) {
  1593. return 1;
  1594. } else if (tmp_ret != 0) {
  1595. ret = 1;
  1596. }
  1597. }
  1598. return ret;
  1599. }
  1600. case XSD_CONTENT_GROUP:
  1601. return model_to_xml_object(node, model->u_group->model, object, style,
  1602. model->min_occurs > 0);
  1603. default:
  1604. break;
  1605. }
  1606. return 1;
  1607. }
  1608. static sdlTypePtr model_array_element(sdlContentModelPtr model) {
  1609. switch (model->kind) {
  1610. case XSD_CONTENT_ELEMENT: {
  1611. if (model->max_occurs == -1 || model->max_occurs > 1) {
  1612. return sdlTypePtr(model->u_element, [] (const void*) {});
  1613. } else {
  1614. return sdlTypePtr();
  1615. }
  1616. }
  1617. case XSD_CONTENT_SEQUENCE:
  1618. case XSD_CONTENT_ALL:
  1619. case XSD_CONTENT_CHOICE: {
  1620. if (model->u_content.size() != 1) {
  1621. return sdlTypePtr();
  1622. }
  1623. return model_array_element(model->u_content[0]);
  1624. }
  1625. case XSD_CONTENT_GROUP:
  1626. return model_array_element(model->u_group->model);
  1627. default:
  1628. break;
  1629. }
  1630. return sdlTypePtr();
  1631. }
  1632. static
  1633. xmlNodePtr to_xml_object(encodeType* type, const Variant& data_, int style,
  1634. xmlNodePtr parent) {
  1635. xmlNodePtr xmlParam;
  1636. sdlType *sdlType = type->sdl_type;
  1637. Variant data = data_;
  1638. if (data.isNull()) {
  1639. xmlParam = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1640. xmlAddChild(parent, xmlParam);
  1641. if (style == SOAP_ENCODED) {
  1642. set_xsi_nil(xmlParam);
  1643. set_ns_and_type(xmlParam, type);
  1644. }
  1645. return xmlParam;
  1646. }
  1647. Array prop;
  1648. if (data.isObject() || data.isArray()) {
  1649. prop = data.toArray();
  1650. }
  1651. if (sdlType) {
  1652. if (sdlType->kind == XSD_TYPEKIND_RESTRICTION &&
  1653. sdlType->encode && type != &sdlType->encode->details) {
  1654. encodePtr enc = sdlType->encode;
  1655. while (enc && enc->details.sdl_type &&
  1656. enc->details.sdl_type->kind != XSD_TYPEKIND_SIMPLE &&
  1657. enc->details.sdl_type->kind != XSD_TYPEKIND_LIST &&
  1658. enc->details.sdl_type->kind != XSD_TYPEKIND_UNION) {
  1659. enc = enc->details.sdl_type->encode;
  1660. }
  1661. if (enc) {
  1662. auto const tmp = get_property(data, "_");
  1663. if (tmp.m_type != KindOfUninit) {
  1664. xmlParam = master_to_xml(enc, tvAsCVarRef(tmp), style, parent);
  1665. } else if (prop.isNull()) {
  1666. xmlParam = master_to_xml(enc, data, style, parent);
  1667. } else {
  1668. xmlParam = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1669. xmlAddChild(parent, xmlParam);
  1670. }
  1671. } else {
  1672. xmlParam = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1673. xmlAddChild(parent, xmlParam);
  1674. }
  1675. } else if (sdlType->kind == XSD_TYPEKIND_EXTENSION &&
  1676. sdlType->encode && type != &sdlType->encode->details) {
  1677. if (sdlType->encode->details.sdl_type &&
  1678. sdlType->encode->details.sdl_type->kind != XSD_TYPEKIND_SIMPLE &&
  1679. sdlType->encode->details.sdl_type->kind != XSD_TYPEKIND_LIST &&
  1680. sdlType->encode->details.sdl_type->kind != XSD_TYPEKIND_UNION) {
  1681. xmlParam = master_to_xml_int(sdlType->encode, data, style,
  1682. parent, false);
  1683. } else {
  1684. auto const enc = sdlType->encode;
  1685. auto const tmp = get_property(data, "_");
  1686. if (tmp.m_type != KindOfUninit) {
  1687. xmlParam = master_to_xml(enc, tvAsCVarRef(tmp), style, parent);
  1688. } else if (prop.isNull()) {
  1689. xmlParam = master_to_xml(enc, data, style, parent);
  1690. } else {
  1691. xmlParam = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1692. xmlAddChild(parent, xmlParam);
  1693. }
  1694. }
  1695. } else {
  1696. xmlParam = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1697. xmlAddChild(parent, xmlParam);
  1698. }
  1699. if (soap_check_zval_ref(data, xmlParam)) {
  1700. return xmlParam;
  1701. }
  1702. if (!prop.isNull()) {
  1703. sdlTypePtr array_el;
  1704. if (data.isArray() && data.toArray()->isVectorData() &&
  1705. sdlType->attributes.empty() && sdlType->model != nullptr &&
  1706. (array_el = model_array_element(sdlType->model)) != nullptr) {
  1707. for (ArrayIter iter(prop); iter; ++iter) {
  1708. Variant val = iter.second();
  1709. xmlNodePtr property;
  1710. if (val.isNull() && array_el->nillable) {
  1711. property = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1712. xmlAddChild(xmlParam, property);
  1713. set_xsi_nil(property);
  1714. } else {
  1715. property = master_to_xml(array_el->encode, val, style, xmlParam);
  1716. }
  1717. xmlNodeSetName(property, BAD_CAST(array_el->name.c_str()));
  1718. if (style == SOAP_LITERAL && !array_el->namens.empty() &&
  1719. array_el->form == XSD_FORM_QUALIFIED) {
  1720. xmlNsPtr nsp = encode_add_ns(property, array_el->namens.c_str());
  1721. xmlSetNs(property, nsp);
  1722. }
  1723. }
  1724. } else if (sdlType->model) {
  1725. model_to_xml_object(xmlParam, sdlType->model, data, style, 1);
  1726. }
  1727. if (!sdlType->attributes.empty()) {
  1728. for (auto const& iter : sdlType->attributes) {
  1729. sdlAttributePtr attr = iter.second;
  1730. if (!attr->name.empty()) {
  1731. auto const rattr = get_property(data, attr->name.c_str());
  1732. if (rattr.m_type != KindOfUninit) {
  1733. xmlNodePtr dummy = master_to_xml(attr->encode, tvAsCVarRef(rattr),
  1734. SOAP_LITERAL, xmlParam);
  1735. if (dummy->children && dummy->children->content) {
  1736. if (!attr->fixed.empty() &&
  1737. attr->fixed != (char*)dummy->children->content) {
  1738. throw SoapException("Encoding: Attribute '%s' has fixed "
  1739. "value '%s' (value '%s' is not allowed)",
  1740. attr->name.c_str(), attr->fixed.c_str(),
  1741. dummy->children->content);
  1742. }
  1743. /* we need to handle xml: namespace specially, since it is
  1744. an implicit schema. Otherwise, use form. */
  1745. if (!strncmp(attr->namens.c_str(), XML_NAMESPACE,
  1746. sizeof(XML_NAMESPACE)) ||
  1747. attr->form == XSD_FORM_QUALIFIED) {
  1748. xmlNsPtr nsp = encode_add_ns(xmlParam, attr->namens.c_str());
  1749. xmlSetNsProp(xmlParam, nsp, BAD_CAST(attr->name.c_str()),
  1750. dummy->children->content);
  1751. } else {
  1752. xmlSetProp(xmlParam, BAD_CAST(attr->name.c_str()),
  1753. dummy->children->content);
  1754. }
  1755. }
  1756. xmlUnlinkNode(dummy);
  1757. xmlFreeNode(dummy);
  1758. }
  1759. }
  1760. }
  1761. }
  1762. }
  1763. if (style == SOAP_ENCODED) {
  1764. set_ns_and_type(xmlParam, type);
  1765. }
  1766. } else {
  1767. xmlParam = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1768. xmlAddChild(parent, xmlParam);
  1769. if (soap_check_zval_ref(data, xmlParam)) {
  1770. return xmlParam;
  1771. }
  1772. if (!prop.isNull()) {
  1773. for (ArrayIter iter(prop); iter; ++iter) {
  1774. Variant key = iter.first();
  1775. Variant zprop = iter.second();
  1776. xmlNodePtr property = master_to_xml(
  1777. get_conversion(dataTypeToSoap(zprop.getType())),
  1778. zprop, style, xmlParam);
  1779. if (key.isString()) {
  1780. String skey = key.toString();
  1781. const char *prop_name;
  1782. if (data.isObject()) {
  1783. const char *class_name;
  1784. zend_unmangle_property_name(skey.data(), skey.size(),
  1785. &class_name, &prop_name);
  1786. } else {
  1787. prop_name = skey.data();
  1788. }
  1789. if (prop_name) {
  1790. xmlNodeSetName(property, BAD_CAST(prop_name));
  1791. }
  1792. }
  1793. }
  1794. }
  1795. if (style == SOAP_ENCODED) {
  1796. set_ns_and_type(xmlParam, type);
  1797. }
  1798. }
  1799. return xmlParam;
  1800. }
  1801. /* Array encode/decode */
  1802. static xmlNodePtr guess_array_map(encodeType* /*type*/, const Variant& data,
  1803. int style, xmlNodePtr parent) {
  1804. encodePtr enc;
  1805. if (data.isArray()) {
  1806. if (!data.toArray()->isVectorData()) {
  1807. enc = get_conversion(APACHE_MAP);
  1808. } else {
  1809. enc = get_conversion(SOAP_ENC_ARRAY);
  1810. }
  1811. }
  1812. if (!enc) {
  1813. enc = get_conversion(dataTypeToSoap(KindOfNull));
  1814. }
  1815. return master_to_xml(enc, data, style, parent);
  1816. }
  1817. static int calc_dimension_12(const char* str) {
  1818. int i = 0, flag = 0;
  1819. while (*str != '\0' && (*str < '0' || *str > '9') && (*str != '*')) {
  1820. str++;
  1821. }
  1822. if (*str == '*') {
  1823. i++;
  1824. str++;
  1825. }
  1826. while (*str != '\0') {
  1827. if (*str >= '0' && *str <= '9') {
  1828. if (flag == 0) {
  1829. i++;
  1830. flag = 1;
  1831. }
  1832. } else if (*str == '*') {
  1833. throw SoapException("Encoding: '*' may only be first arraySize value"
  1834. " in list");
  1835. } else {
  1836. flag = 0;
  1837. }
  1838. str++;
  1839. }
  1840. return i;
  1841. }
  1842. static int* get_position_12(int dimension, const char* str) {
  1843. int *pos;
  1844. int i = -1, flag = 0;
  1845. pos = (int*)req::calloc_noptrs(dimension, sizeof(int));
  1846. while (*str != '\0' && (*str < '0' || *str > '9') && (*str != '*')) {
  1847. str++;
  1848. }
  1849. if (*str == '*') {
  1850. str++;
  1851. i++;
  1852. }
  1853. while (*str != '\0') {
  1854. if (*str >= '0' && *str <= '9') {
  1855. if (flag == 0) {
  1856. i++;
  1857. flag = 1;
  1858. }
  1859. pos[i] = (pos[i]*10)+(*str-'0');
  1860. } else if (*str == '*') {
  1861. throw SoapException("Encoding: '*' may only be first arraySize value in list");
  1862. } else {
  1863. flag = 0;
  1864. }
  1865. str++;
  1866. }
  1867. return pos;
  1868. }
  1869. static int calc_dimension(const char* str) {
  1870. int i = 1;
  1871. while (*str != ']' && *str != '\0') {
  1872. if (*str == ',') {
  1873. i++;
  1874. }
  1875. str++;
  1876. }
  1877. return i;
  1878. }
  1879. static void get_position_ex(int dimension, const char* str, int** pos) {
  1880. int i = 0;
  1881. memset(*pos,0,sizeof(int)*dimension);
  1882. while (*str != ']' && *str != '\0' && i < dimension) {
  1883. if (*str >= '0' && *str <= '9') {
  1884. (*pos)[i] = ((*pos)[i]*10)+(*str-'0');
  1885. } else if (*str == ',') {
  1886. i++;
  1887. }
  1888. str++;
  1889. }
  1890. }
  1891. static int* get_position(int dimension, const char* str) {
  1892. int *pos = (int*)req::malloc_noptrs(sizeof(int) * dimension);
  1893. get_position_ex(dimension, str, &pos);
  1894. return pos;
  1895. }
  1896. static void add_xml_array_elements(xmlNodePtr xmlParam,
  1897. sdlTypePtr type,
  1898. encodePtr enc,
  1899. xmlNsPtr ns,
  1900. int dimension ,
  1901. int* dims,
  1902. const Variant& data,
  1903. int style) {
  1904. if (data.isArray()) {
  1905. Array arr = data.toArray();
  1906. ArrayIter iter(arr);
  1907. for (int j=0; j<dims[0]; j++) {
  1908. Variant zdata = iter.second(); ++iter;
  1909. if (dimension == 1) {
  1910. xmlNodePtr xparam;
  1911. if (!zdata.isNull()) {
  1912. if (enc == nullptr) {
  1913. xparam = master_to_xml(
  1914. get_conversion(dataTypeToSoap(zdata.getType())), zdata,
  1915. style, xmlParam
  1916. );
  1917. } else {
  1918. xparam = master_to_xml(enc, zdata, style, xmlParam);
  1919. }
  1920. } else {
  1921. xparam = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1922. xmlAddChild(xmlParam, xparam);
  1923. }
  1924. if (type) {
  1925. xmlNodeSetName(xparam, BAD_CAST(type->name.c_str()));
  1926. } else if (style == SOAP_LITERAL && enc &&
  1927. !enc->details.type_str.empty()) {
  1928. xmlNodeSetName(xparam, BAD_CAST(enc->details.type_str.c_str()));
  1929. xmlSetNs(xparam, ns);
  1930. } else {
  1931. xmlNodeSetName(xparam, BAD_CAST("item"));
  1932. }
  1933. } else {
  1934. if (!zdata.isNull()) {
  1935. add_xml_array_elements(xmlParam, type, enc, ns, dimension-1, dims+1,
  1936. zdata, style);
  1937. } else {
  1938. add_xml_array_elements(xmlParam, type, enc, ns, dimension-1, dims+1,
  1939. uninit_null(), style);
  1940. }
  1941. }
  1942. }
  1943. } else {
  1944. for (int j=0; j<dims[0]; j++) {
  1945. if (dimension == 1) {
  1946. xmlNodePtr xparam;
  1947. xparam = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  1948. xmlAddChild(xmlParam, xparam);
  1949. if (type) {
  1950. xmlNodeSetName(xparam, BAD_CAST(type->name.c_str()));
  1951. } else if (style == SOAP_LITERAL && enc &&
  1952. !enc->details.type_str.empty()) {
  1953. xmlNodeSetName(xparam, BAD_CAST(enc->details.type_str.c_str()));
  1954. xmlSetNs(xparam, ns);
  1955. } else {
  1956. xmlNodeSetName(xparam, BAD_CAST("item"));
  1957. }
  1958. } else {
  1959. add_xml_array_elements(xmlParam, type, enc, ns, dimension-1, dims+1,
  1960. uninit_null(), style);
  1961. }
  1962. }
  1963. }
  1964. }
  1965. static std::shared_ptr<sdlExtraAttribute>
  1966. get_extra_attributes(sdlType *sdl_type,
  1967. const char *type,
  1968. const char *wsdl_type) {
  1969. if (sdl_type) {
  1970. sdlAttributeMap::const_iterator iterAttributes =
  1971. sdl_type->attributes.find(type);
  1972. if (iterAttributes != sdl_type->attributes.end()) {
  1973. sdlExtraAttributeMap::const_iterator iterExtraAttributes =
  1974. iterAttributes->second->extraAttributes.find(wsdl_type);
  1975. if (iterExtraAttributes !=
  1976. iterAttributes->second->extraAttributes.end()) {
  1977. return iterExtraAttributes->second;
  1978. }
  1979. }
  1980. }
  1981. return std::shared_ptr<sdlExtraAttribute>();
  1982. }
  1983. static
  1984. xmlNodePtr to_xml_array(encodeType* type, const Variant& data_, int style,
  1985. xmlNodePtr parent) {
  1986. USE_SOAP_GLOBAL;
  1987. sdlType *sdl_type = type->sdl_type;
  1988. sdlTypePtr element_type;
  1989. std::string array_type, array_size;
  1990. int i;
  1991. xmlNodePtr xmlParam;
  1992. encodePtr enc;
  1993. int dimension = 1;
  1994. int* dims = nullptr;
  1995. int soap_version;
  1996. Variant array_copy;
  1997. Variant data = data_;
  1998. soap_version = SOAP_GLOBAL(soap_version);
  1999. xmlParam = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  2000. xmlAddChild(parent, xmlParam);
  2001. if (data.isNull()) {
  2002. if (style == SOAP_ENCODED) {
  2003. set_xsi_nil(xmlParam);
  2004. if (SOAP_GLOBAL(features) & SOAP_USE_XSI_ARRAY_TYPE) {
  2005. set_ns_and_type_ex(xmlParam, (soap_version == SOAP_1_1) ?
  2006. SOAP_1_1_ENC_NAMESPACE : SOAP_1_2_ENC_NAMESPACE,
  2007. "Array");
  2008. } else {
  2009. set_ns_and_type(xmlParam, type);
  2010. }
  2011. }
  2012. return xmlParam;
  2013. }
  2014. if (data.isObject() &&
  2015. data.toObject().instanceof(SystemLib::s_HH_IteratorClass)) {
  2016. array_copy = Array::Create();
  2017. for (ArrayIter iter(data.toObject().get()); iter; ++iter) {
  2018. if (!iter.first().isNull() && iter.first().isString()) {
  2019. array_copy.asArrRef().set(iter.first(), iter.second());
  2020. } else {
  2021. array_copy.asArrRef().append(iter.second());
  2022. }
  2023. }
  2024. data = array_copy;
  2025. }
  2026. if (data.isArray()) {
  2027. std::shared_ptr<sdlExtraAttribute> ext;
  2028. sdlTypeMap::const_iterator iterElements;
  2029. sdlAttributeMap::const_iterator iterAttributes;
  2030. sdlExtraAttributeMap::const_iterator iterExtraAttributes;
  2031. sdlTypePtr elementType;
  2032. i = data.toArray().size();
  2033. if ((ext = get_extra_attributes(sdl_type,
  2034. SOAP_1_1_ENC_NAMESPACE":arrayType",
  2035. WSDL_NAMESPACE":arrayType"))) {
  2036. String value(ext->val);
  2037. char *end = const_cast<char*>(strrchr(value.data(), '['));
  2038. if (end) {
  2039. *end = '\0';
  2040. end++;
  2041. dimension = calc_dimension(end);
  2042. }
  2043. if (!ext->ns.empty()) {
  2044. enc = get_encoder(SOAP_GLOBAL(sdl), ext->ns.c_str(), value.data());
  2045. get_type_str(xmlParam, ext->ns.c_str(), value.data(), array_type);
  2046. } else {
  2047. array_type += value.data();
  2048. }
  2049. dims = (int*)req::malloc_noptrs(sizeof(int) * dimension);
  2050. dims[0] = i;
  2051. Array el = data.toArray();
  2052. for (i = 1; i < dimension; i++) {
  2053. if (!el.empty()) {
  2054. ArrayIter iter(el);
  2055. Variant tmp = iter.second();
  2056. if (tmp.isArray()) {
  2057. dims[i] = tmp.toArray().size();
  2058. } else {
  2059. dims[i] = 0;
  2060. }
  2061. }
  2062. }
  2063. array_size += folly::to<string>(dims[0]);
  2064. for (i=1; i<dimension; i++) {
  2065. array_size += ',';
  2066. array_size += folly::to<string>(dims[i]);
  2067. }
  2068. } else if ((ext = get_extra_attributes
  2069. (sdl_type,
  2070. SOAP_1_2_ENC_NAMESPACE":itemType",
  2071. WSDL_NAMESPACE":itemType"))) {
  2072. if (!ext->ns.empty()) {
  2073. enc = get_encoder(SOAP_GLOBAL(sdl), ext->ns.c_str(), ext->val.c_str());
  2074. get_type_str(xmlParam, ext->ns.c_str(), ext->val.c_str(), array_type);
  2075. } else {
  2076. array_type += ext->val;
  2077. }
  2078. if ((iterAttributes =
  2079. sdl_type->attributes.find(SOAP_1_2_ENC_NAMESPACE":arraySize")) !=
  2080. sdl_type->attributes.end()) {
  2081. if ((iterExtraAttributes =
  2082. iterAttributes->second->extraAttributes.find
  2083. (WSDL_NAMESPACE":arraySize")) !=
  2084. iterAttributes->second->extraAttributes.end()) {
  2085. auto ext = iterExtraAttributes->second;
  2086. dimension = calc_dimension_12(ext->val.c_str());
  2087. dims = get_position_12(dimension, ext->val.c_str());
  2088. if (dims[0] == 0) {dims[0] = i;}
  2089. array_size += folly::to<string>(dims[0]);
  2090. for (i=1; i<dimension; i++) {
  2091. array_size += ',';
  2092. array_size += folly::to<string>(dims[i]);
  2093. }
  2094. }
  2095. } else {
  2096. dims = (int*)req::malloc_noptrs(sizeof(int));
  2097. *dims = 0;
  2098. array_size += folly::to<string>(i);
  2099. }
  2100. } else if ((ext = get_extra_attributes
  2101. (sdl_type,
  2102. SOAP_1_2_ENC_NAMESPACE":arraySize",
  2103. WSDL_NAMESPACE":arraySize"))) {
  2104. dimension = calc_dimension_12(ext->val.c_str());
  2105. dims = get_position_12(dimension, ext->val.c_str());
  2106. if (dims[0] == 0) {dims[0] = i;}
  2107. array_size += folly::to<string>(dims[0]);
  2108. for (i=1; i<dimension; i++) {
  2109. array_size += ',';
  2110. array_size += folly::to<string>(dims[i]);
  2111. }
  2112. if (sdl_type && sdl_type->elements.size() == 1 &&
  2113. (elementType = sdl_type->elements[0]) != nullptr &&
  2114. elementType->encode &&
  2115. !elementType->encode->details.type_str.empty()) {
  2116. elementType = sdl_type->elements[0];
  2117. element_type = elementType;
  2118. enc = elementType->encode;
  2119. get_type_str(xmlParam, elementType->encode->details.ns.c_str(),
  2120. elementType->encode->details.type_str.c_str(),
  2121. array_type);
  2122. } else {
  2123. enc = get_array_type(xmlParam, data, array_type);
  2124. }
  2125. } else if
  2126. (sdl_type && sdl_type->elements.size() == 1 &&
  2127. (elementType = sdl_type->elements[0]) != nullptr &&
  2128. elementType->encode &&
  2129. !elementType->encode->details.type_str.empty()) {
  2130. element_type = elementType;
  2131. enc = elementType->encode;
  2132. get_type_str(xmlParam, elementType->encode->details.ns.c_str(),
  2133. elementType->encode->details.type_str.c_str(), array_type);
  2134. array_size += folly::to<string>(i);
  2135. dims = (int*)req::malloc_noptrs(sizeof(int) * dimension);
  2136. dims[0] = i;
  2137. } else {
  2138. enc = get_array_type(xmlParam, data, array_type);
  2139. array_size += folly::to<string>(i);
  2140. dims = (int*)req::malloc_noptrs(sizeof(int) * dimension);
  2141. dims[0] = i;
  2142. }
  2143. if (style == SOAP_ENCODED) {
  2144. if (soap_version == SOAP_1_1) {
  2145. if (array_type == "xsd:anyType") {
  2146. array_type = "xsd:ur-type";
  2147. }
  2148. array_type += '[';
  2149. array_type += array_size;
  2150. array_type += ']';
  2151. set_ns_prop(xmlParam, SOAP_1_1_ENC_NAMESPACE, "arrayType",
  2152. array_type.c_str());
  2153. } else {
  2154. string replaced;
  2155. replaced.reserve(array_size.size());
  2156. for (int i2 = 0; i2 < (int)array_size.size(); i2++) {
  2157. char ch = array_size[i2];
  2158. if (ch == ',') {
  2159. replaced += ' ';
  2160. } else {
  2161. replaced += ch;
  2162. }
  2163. }
  2164. set_ns_prop(xmlParam, SOAP_1_2_ENC_NAMESPACE, "itemType",
  2165. array_type.c_str());
  2166. set_ns_prop(xmlParam, SOAP_1_2_ENC_NAMESPACE, "arraySize",
  2167. replaced.c_str());
  2168. }
  2169. }
  2170. add_xml_array_elements(xmlParam, element_type, enc,
  2171. enc ? encode_add_ns(xmlParam,
  2172. enc->details.ns.c_str()) : nullptr,
  2173. dimension, dims, data, style);
  2174. req::free(dims);
  2175. }
  2176. if (style == SOAP_ENCODED) {
  2177. if (SOAP_GLOBAL(features) & SOAP_USE_XSI_ARRAY_TYPE) {
  2178. set_ns_and_type_ex
  2179. (xmlParam, (soap_version == SOAP_1_1) ?
  2180. SOAP_1_1_ENC_NAMESPACE : SOAP_1_2_ENC_NAMESPACE, "Array");
  2181. } else {
  2182. set_ns_and_type(xmlParam, type);
  2183. }
  2184. }
  2185. return xmlParam;
  2186. }
  2187. static Variant to_zval_array(encodeType* type, xmlNodePtr data) {
  2188. USE_SOAP_GLOBAL;
  2189. Variant ret;
  2190. xmlNodePtr trav;
  2191. encodePtr enc;
  2192. int dimension = 1;
  2193. int* dims = nullptr;
  2194. int* pos = nullptr;
  2195. xmlAttrPtr attr;
  2196. sdl *sdl;
  2197. sdlAttributePtr arrayType;
  2198. std::shared_ptr<sdlExtraAttribute> ext;
  2199. sdlTypePtr elementType;
  2200. FIND_XML_NULL(data, ret);
  2201. sdl = SOAP_GLOBAL(sdl);
  2202. if (data &&
  2203. (attr = get_attribute(data->properties,"arrayType")) &&
  2204. attr->children && attr->children->content) {
  2205. xmlNsPtr nsptr;
  2206. string type, ns;
  2207. parse_namespace(attr->children->content, type, ns);
  2208. nsptr = xmlSearchNs(attr->doc, attr->parent, NS_STRING(ns));
  2209. String stype(type);
  2210. char *end = const_cast<char*>(strrchr(stype.data(), '['));
  2211. if (end) {
  2212. *end = '\0';
  2213. dimension = calc_dimension(end+1);
  2214. dims = get_position(dimension, end+1);
  2215. }
  2216. if (nsptr != nullptr) {
  2217. enc = get_encoder(sdl, (char*)nsptr->href, stype.data());
  2218. }
  2219. } else if ((attr = get_attribute(data->properties,"itemType")) &&
  2220. attr->children &&
  2221. attr->children->content) {
  2222. string type, ns;
  2223. parse_namespace(attr->children->content, type, ns);
  2224. xmlNsPtr nsptr;
  2225. nsptr = xmlSearchNs(attr->doc, attr->parent, NS_STRING(ns));
  2226. if (nsptr != nullptr) {
  2227. enc = get_encoder(sdl, (char*)nsptr->href, type.data());
  2228. }
  2229. if ((attr = get_attribute(data->properties,"arraySize")) &&
  2230. attr->children && attr->children->content) {
  2231. dimension = calc_dimension_12((char*)attr->children->content);
  2232. dims = get_position_12(dimension, (char*)attr->children->content);
  2233. } else {
  2234. dims = (int*)req::malloc_noptrs(sizeof(int));
  2235. *dims = 0;
  2236. }
  2237. } else if ((attr = get_attribute(data->properties,"arraySize")) &&
  2238. attr->children && attr->children->content) {
  2239. dimension = calc_dimension_12((char*)attr->children->content);
  2240. dims = get_position_12(dimension, (char*)attr->children->content);
  2241. } else if ((ext = get_extra_attributes
  2242. (type->sdl_type,
  2243. SOAP_1_1_ENC_NAMESPACE":arrayType",
  2244. WSDL_NAMESPACE":arrayType"))) {
  2245. String type(ext->val);
  2246. char *end = const_cast<char*>(strrchr(type.data(), '['));
  2247. if (end) {
  2248. *end = '\0';
  2249. }
  2250. if (!ext->ns.empty()) {
  2251. enc = get_encoder(sdl, ext->ns.c_str(), type.data());
  2252. }
  2253. dims = (int*)req::malloc_noptrs(sizeof(int));
  2254. *dims = 0;
  2255. } else if ((ext = get_extra_attributes
  2256. (type->sdl_type,
  2257. SOAP_1_2_ENC_NAMESPACE":itemType",
  2258. WSDL_NAMESPACE":itemType"))) {
  2259. if (!ext->ns.empty()) {
  2260. enc = get_encoder(sdl, ext->ns.c_str(), ext->val.c_str());
  2261. }
  2262. if ((ext = get_extra_attributes
  2263. (type->sdl_type,
  2264. SOAP_1_2_ENC_NAMESPACE":arraySize",
  2265. WSDL_NAMESPACE":arraySize"))) {
  2266. dimension = calc_dimension_12(ext->val.c_str());
  2267. dims = get_position_12(dimension, ext->val.c_str());
  2268. } else {
  2269. dims = (int*)req::malloc_noptrs(sizeof(int));
  2270. *dims = 0;
  2271. }
  2272. } else if ((ext = get_extra_attributes
  2273. (type->sdl_type,
  2274. SOAP_1_2_ENC_NAMESPACE":arraySize",
  2275. WSDL_NAMESPACE":arraySize"))) {
  2276. dimension = calc_dimension_12(ext->val.c_str());
  2277. dims = get_position_12(dimension, ext->val.c_str());
  2278. if (type->sdl_type && type->sdl_type->elements.size() == 1 &&
  2279. (elementType = type->sdl_type->elements[0]) != nullptr &&
  2280. elementType->encode) {
  2281. enc = elementType->encode;
  2282. }
  2283. } else if (type->sdl_type && type->sdl_type->elements.size() == 1 &&
  2284. (elementType = type->sdl_type->elements[0]) != nullptr &&
  2285. elementType->encode) {
  2286. enc = elementType->encode;
  2287. }
  2288. if (dims == nullptr) {
  2289. dimension = 1;
  2290. dims = (int*)req::malloc_noptrs(sizeof(int));
  2291. *dims = 0;
  2292. }
  2293. pos = (int*)req::calloc_noptrs(sizeof(int), dimension);
  2294. if (data && (attr = get_attribute(data->properties,"offset")) &&
  2295. attr->children && attr->children->content) {
  2296. char* tmp = strrchr((char*)attr->children->content,'[');
  2297. if (tmp == nullptr) {
  2298. tmp = (char*)attr->children->content;
  2299. }
  2300. get_position_ex(dimension, tmp, &pos);
  2301. }
  2302. ret = Array::Create();
  2303. trav = data->children;
  2304. while (trav) {
  2305. if (trav->type == XML_ELEMENT_NODE) {
  2306. int i;
  2307. xmlAttrPtr position = get_attribute(trav->properties,"position");
  2308. Variant tmpVal = master_to_zval(enc, trav);
  2309. if (position != nullptr && position->children &&
  2310. position->children->content) {
  2311. char* tmp = strrchr((char*)position->children->content, '[');
  2312. if (tmp == nullptr) {
  2313. tmp = (char*)position->children->content;
  2314. }
  2315. get_position_ex(dimension, tmp, &pos);
  2316. }
  2317. /* Get/Create intermediate arrays for multidimensional arrays */
  2318. i = 0;
  2319. tv_lval ar = ret.asTypedValue();
  2320. while (i < dimension-1) {
  2321. auto& arr = asArrRef(ar);
  2322. if (!arr.exists(pos[i])) {
  2323. arr.set(pos[i], Array::Create());
  2324. }
  2325. ar = arr.lval(pos[i]);
  2326. i++;
  2327. }
  2328. asArrRef(ar).set(pos[i], tmpVal);
  2329. /* Increment position */
  2330. i = dimension;
  2331. while (i > 0) {
  2332. i--;
  2333. pos[i]++;
  2334. if (pos[i] >= dims[i]) {
  2335. if (i > 0) {
  2336. pos[i] = 0;
  2337. } else {
  2338. /* TODO: Array index overflow */
  2339. }
  2340. } else {
  2341. break;
  2342. }
  2343. }
  2344. }
  2345. trav = trav->next;
  2346. }
  2347. req::free(dims);
  2348. req::free(pos);
  2349. return ret;
  2350. }
  2351. /* Map encode/decode */
  2352. static xmlNodePtr to_xml_map(encodeType* type, const Variant& data, int style,
  2353. xmlNodePtr parent) {
  2354. xmlNodePtr xmlParam;
  2355. int i;
  2356. xmlParam = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  2357. xmlAddChild(parent, xmlParam);
  2358. FIND_ZVAL_NULL(data, xmlParam, style);
  2359. if (data.isArray()) {
  2360. Array arr = data.toArray();
  2361. i = arr.size();
  2362. ArrayIter iter(arr);
  2363. for (;i > 0;i--) {
  2364. xmlNodePtr xparam, item;
  2365. xmlNodePtr key;
  2366. Variant temp_key = iter.first();
  2367. Variant temp_data = iter.second();
  2368. ++iter;
  2369. item = xmlNewNode(nullptr, BAD_CAST("item"));
  2370. xmlAddChild(xmlParam, item);
  2371. key = xmlNewNode(nullptr, BAD_CAST("key"));
  2372. xmlAddChild(item,key);
  2373. if (temp_key.isString()) {
  2374. if (style == SOAP_ENCODED) {
  2375. set_xsi_type(key, "xsd:string");
  2376. }
  2377. xmlNodeSetContent(key, BAD_CAST(temp_key.toString().data()));
  2378. } else {
  2379. if (style == SOAP_ENCODED) {
  2380. set_xsi_type(key, "xsd:int");
  2381. }
  2382. String skey = temp_key.toString();
  2383. xmlNodeSetContentLen(key, BAD_CAST(skey.data()), skey.size());
  2384. }
  2385. xparam = master_to_xml(
  2386. get_conversion(dataTypeToSoap(temp_data.getType())),
  2387. temp_data, style, item
  2388. );
  2389. xmlNodeSetName(xparam, BAD_CAST("value"));
  2390. }
  2391. }
  2392. if (style == SOAP_ENCODED) {
  2393. set_ns_and_type(xmlParam, type);
  2394. }
  2395. return xmlParam;
  2396. }
  2397. static Variant to_zval_map(encodeType* /*type*/, xmlNodePtr data) {
  2398. Variant key, value;
  2399. Array ret;
  2400. xmlNodePtr trav, item, xmlKey, xmlValue;
  2401. FIND_XML_NULL(data, ret);
  2402. if (data && data->children) {
  2403. trav = data->children;
  2404. FOREACHNODE(trav, "item", item) {
  2405. xmlKey = get_node(item->children, "key");
  2406. if (!xmlKey) {
  2407. throw SoapException( "Encoding: Can't decode map, missing key");
  2408. }
  2409. xmlValue = get_node(item->children, "value");
  2410. if (!xmlKey) {
  2411. throw SoapException( "Encoding: Can't decode map, missing value");
  2412. }
  2413. key = master_to_zval(encodePtr(), xmlKey);
  2414. value = master_to_zval(encodePtr(), xmlValue);
  2415. if (key.isString() || key.isInteger()) {
  2416. ret.set(key, value);
  2417. } else {
  2418. throw SoapException( "Encoding: Can't decode map, only Strings or "
  2419. "Longs are allowd as keys");
  2420. }
  2421. }
  2422. ENDFOREACH(trav);
  2423. }
  2424. return ret;
  2425. }
  2426. /* Unknown encode/decode */
  2427. static xmlNodePtr guess_xml_convert(encodeType* /*type*/, const Variant& data,
  2428. int style, xmlNodePtr parent) {
  2429. encodePtr enc = get_conversion(dataTypeToSoap(data.getType()));
  2430. xmlNodePtr ret = master_to_xml_int(enc, data, style, parent, false);
  2431. /*
  2432. if (style == SOAP_LITERAL && SOAP_GLOBAL(sdl)) {
  2433. set_ns_and_type(ret, &enc->details);
  2434. }
  2435. */
  2436. return ret;
  2437. }
  2438. static Variant guess_zval_convert(encodeType* type, xmlNodePtr data) {
  2439. USE_SOAP_GLOBAL;
  2440. encodePtr enc;
  2441. xmlAttrPtr tmpattr;
  2442. xmlChar *type_name = nullptr;
  2443. Variant ret;
  2444. data = check_and_resolve_href(data);
  2445. if (data == nullptr) {
  2446. enc = get_conversion(dataTypeToSoap(KindOfNull));
  2447. } else if (data->properties &&
  2448. get_attribute_ex(data->properties, "nil", XSI_NAMESPACE)) {
  2449. enc = get_conversion(dataTypeToSoap(KindOfNull));
  2450. } else {
  2451. tmpattr = get_attribute_ex(data->properties,"type", XSI_NAMESPACE);
  2452. if (tmpattr != nullptr) {
  2453. type_name = tmpattr->children->content;
  2454. enc = get_encoder_from_prefix(SOAP_GLOBAL(sdl), data,
  2455. tmpattr->children->content);
  2456. if (enc && type == &enc->details) {
  2457. enc.reset();
  2458. }
  2459. if (enc) {
  2460. encodePtr tmp = enc;
  2461. while (tmp && tmp->details.sdl_type != nullptr &&
  2462. tmp->details.sdl_type->kind != XSD_TYPEKIND_COMPLEX) {
  2463. if (enc == tmp->details.sdl_type->encode ||
  2464. tmp == tmp->details.sdl_type->encode) {
  2465. enc.reset();
  2466. break;
  2467. }
  2468. tmp = tmp->details.sdl_type->encode;
  2469. }
  2470. }
  2471. }
  2472. if (!enc) {
  2473. /* Didn't have a type, totally guess here */
  2474. /* Logic: has children = IS_OBJECT else IS_STRING */
  2475. xmlNodePtr trav;
  2476. if (get_attribute(data->properties, "arrayType") ||
  2477. get_attribute(data->properties, "itemType") ||
  2478. get_attribute(data->properties, "arraySize")) {
  2479. enc = get_conversion(SOAP_ENC_ARRAY);
  2480. } else {
  2481. enc = get_conversion(XSD_STRING);
  2482. trav = data->children;
  2483. while (trav != nullptr) {
  2484. if (trav->type == XML_ELEMENT_NODE) {
  2485. enc = get_conversion(SOAP_ENC_OBJECT);
  2486. break;
  2487. }
  2488. trav = trav->next;
  2489. }
  2490. }
  2491. }
  2492. }
  2493. ret = master_to_zval_int(enc, data);
  2494. if (SOAP_GLOBAL(sdl) && type_name && enc->details.sdl_type) {
  2495. Object obj{SoapVar::getClass()};
  2496. SoapVar::setEncType(obj.get(), enc->details.type);
  2497. SoapVar::setEncValue(obj.get(), ret);
  2498. string ns, cptype;
  2499. parse_namespace(type_name, cptype, ns);
  2500. xmlNsPtr nsptr = xmlSearchNs(data->doc, data, NS_STRING(ns));
  2501. SoapVar::setEncSType(obj.get(), cptype);
  2502. if (nsptr) {
  2503. SoapVar::setEncNS(obj.get(), String((char*)nsptr->href, CopyString));
  2504. }
  2505. ret = std::move(obj);
  2506. }
  2507. return ret;
  2508. }
  2509. /* Time encode/decode */
  2510. static xmlNodePtr to_xml_datetime_ex(encodeType* type, const Variant& data,
  2511. const char *format, int style,
  2512. xmlNodePtr parent) {
  2513. /* logic hacked from ext/standard/datetime.c */
  2514. struct tm *ta, tmbuf;
  2515. time_t timestamp;
  2516. int max_reallocs = 5;
  2517. size_t buf_len=64, real_len;
  2518. char *buf;
  2519. char tzbuf[8];
  2520. xmlNodePtr xmlParam = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  2521. xmlAddChild(parent, xmlParam);
  2522. FIND_ZVAL_NULL(data, xmlParam, style);
  2523. if (data.isInteger()) {
  2524. timestamp = data.toInt64();
  2525. ta = localtime_r(&timestamp, &tmbuf);
  2526. /*ta = php_gmtime_r(&timestamp, &tmbuf);*/
  2527. buf = (char *)req::malloc_noptrs(buf_len);
  2528. while ((real_len = strftime(buf, buf_len, format, ta)) == buf_len ||
  2529. real_len == 0) {
  2530. buf_len *= 2;
  2531. buf = (char *)req::realloc_noptrs(buf, buf_len);
  2532. if (!--max_reallocs) break;
  2533. }
  2534. #ifndef _MSC_VER
  2535. /* Time zone support */
  2536. snprintf(tzbuf, sizeof(tzbuf), "%c%02d:%02d",
  2537. (ta->tm_gmtoff < 0) ? '-' : '+', (int)abs(ta->tm_gmtoff / 3600),
  2538. (int)abs( (ta->tm_gmtoff % 3600) / 60 ));
  2539. if (strcmp(tzbuf,"+00:00") == 0) {
  2540. strcpy(tzbuf,"Z");
  2541. real_len++;
  2542. } else {
  2543. real_len += 6;
  2544. }
  2545. #endif
  2546. if (real_len >= buf_len) {
  2547. buf = (char *)req::realloc_noptrs(buf, real_len+1);
  2548. }
  2549. strncat(buf, tzbuf, real_len);
  2550. xmlNodeSetContent(xmlParam, BAD_CAST(buf));
  2551. req::free(buf);
  2552. } else if (data.isString()) {
  2553. String sdata = data.toString();
  2554. xmlNodeSetContentLen(xmlParam, BAD_CAST(sdata.data()), sdata.size());
  2555. }
  2556. if (style == SOAP_ENCODED) {
  2557. set_ns_and_type(xmlParam, type);
  2558. }
  2559. return xmlParam;
  2560. }
  2561. static
  2562. xmlNodePtr to_xml_duration(encodeType* type, const Variant& data, int style,
  2563. xmlNodePtr parent) {
  2564. // TODO: '-'?P([0-9]+Y)?([0-9]+M)?([0-9]+D)?T([0-9]+H)?([0-9]+M)?([0-9]+S)?
  2565. return to_xml_string(type, data, style, parent);
  2566. }
  2567. static
  2568. xmlNodePtr to_xml_datetime(encodeType* type, const Variant& data, int style,
  2569. xmlNodePtr parent) {
  2570. return to_xml_datetime_ex(type, data, "%Y-%m-%dT%H:%M:%S", style, parent);
  2571. }
  2572. static xmlNodePtr to_xml_time(encodeType* type, const Variant& data, int style,
  2573. xmlNodePtr parent) {
  2574. /* TODO: microsecconds */
  2575. return to_xml_datetime_ex(type, data, "%H:%M:%S", style, parent);
  2576. }
  2577. static xmlNodePtr to_xml_date(encodeType* type, const Variant& data, int style,
  2578. xmlNodePtr parent) {
  2579. return to_xml_datetime_ex(type, data, "%Y-%m-%d", style, parent);
  2580. }
  2581. static xmlNodePtr to_xml_gyearmonth(encodeType* type, const Variant& data,
  2582. int style, xmlNodePtr parent) {
  2583. return to_xml_datetime_ex(type, data, "%Y-%m", style, parent);
  2584. }
  2585. static xmlNodePtr to_xml_gyear(encodeType* type, const Variant& data, int style,
  2586. xmlNodePtr parent) {
  2587. return to_xml_datetime_ex(type, data, "%Y", style, parent);
  2588. }
  2589. static
  2590. xmlNodePtr to_xml_gmonthday(encodeType* type, const Variant& data, int style,
  2591. xmlNodePtr parent) {
  2592. return to_xml_datetime_ex(type, data, "--%m-%d", style, parent);
  2593. }
  2594. static xmlNodePtr to_xml_gday(encodeType* type, const Variant& data, int style,
  2595. xmlNodePtr parent) {
  2596. return to_xml_datetime_ex(type, data, "---%d", style, parent);
  2597. }
  2598. static
  2599. xmlNodePtr to_xml_gmonth(encodeType* type, const Variant& data, int style,
  2600. xmlNodePtr parent) {
  2601. return to_xml_datetime_ex(type, data, "--%m--", style, parent);
  2602. }
  2603. static Variant to_zval_list(encodeType* enc, xmlNodePtr data) {
  2604. /*FIXME*/
  2605. return to_zval_stringc(enc, data);
  2606. }
  2607. static xmlNodePtr to_xml_list(encodeType* enc, const Variant& data, int style,
  2608. xmlNodePtr parent) {
  2609. encodePtr list_enc;
  2610. if (enc->sdl_type && enc->sdl_type->kind == XSD_TYPEKIND_LIST &&
  2611. !enc->sdl_type->elements.empty()) {
  2612. list_enc = enc->sdl_type->elements[0]->encode;
  2613. }
  2614. xmlNodePtr ret = xmlNewNode(nullptr, BAD_CAST("BOGUS"));
  2615. xmlAddChild(parent, ret);
  2616. FIND_ZVAL_NULL(data, ret, style);
  2617. if (data.isArray()) {
  2618. Variant tmp;
  2619. string list;
  2620. Array ht = data.toArray();
  2621. for (ArrayIter iter(ht); iter; ++iter) {
  2622. xmlNodePtr dummy = master_to_xml(list_enc, tmp, SOAP_LITERAL, ret);
  2623. if (dummy && dummy->children && dummy->children->content) {
  2624. if (!list.empty()) {
  2625. list += ' ';
  2626. }
  2627. list += (char*)dummy->children->content;
  2628. } else {
  2629. throw SoapException("Encoding: Violation of encoding rules");
  2630. }
  2631. xmlUnlinkNode(dummy);
  2632. xmlFreeNode(dummy);
  2633. }
  2634. xmlNodeSetContentLen(ret, BAD_CAST(list.c_str()), list.size());
  2635. } else {
  2636. String sdata = data.toString();
  2637. char *str = req::strndup(sdata.data(), sdata.size());
  2638. whiteSpace_collapse(BAD_CAST(str));
  2639. char *start = str;
  2640. char *next;
  2641. string list;
  2642. while (start != nullptr && *start != '\0') {
  2643. xmlNodePtr dummy;
  2644. Variant dummy_zval;
  2645. next = strchr(start,' ');
  2646. if (next != nullptr) {
  2647. *next = '\0';
  2648. next++;
  2649. }
  2650. dummy_zval = String(start);
  2651. dummy = master_to_xml(list_enc, dummy_zval, SOAP_LITERAL, ret);
  2652. if (dummy && dummy->children && dummy->children->content) {
  2653. if (!list.empty()) {
  2654. list += ' ';
  2655. }
  2656. list += (char*)dummy->children->content;
  2657. } else {
  2658. throw SoapException("Encoding: Violation of encoding rules");
  2659. }
  2660. xmlUnlinkNode(dummy);
  2661. xmlFreeNode(dummy);
  2662. start = next;
  2663. }
  2664. xmlNodeSetContentLen(ret, BAD_CAST(list.c_str()), list.size());
  2665. req::free(str);
  2666. }
  2667. return ret;
  2668. }
  2669. static xmlNodePtr to_xml_list1(encodeType* enc, const Variant& data, int style,
  2670. xmlNodePtr parent) {
  2671. /*FIXME: minLength=1 */
  2672. return to_xml_list(enc,data,style, parent);
  2673. }
  2674. static Variant to_zval_union(encodeType* enc, xmlNodePtr data) {
  2675. /*FIXME*/
  2676. return to_zval_list(enc, data);
  2677. }
  2678. static xmlNodePtr to_xml_union(encodeType* enc, const Variant& data, int style,
  2679. xmlNodePtr parent) {
  2680. /*FIXME*/
  2681. return to_xml_list(enc,data,style, parent);
  2682. }
  2683. static Variant to_zval_any(encodeType* /*type*/, xmlNodePtr data) {
  2684. USE_SOAP_GLOBAL;
  2685. xmlBufferPtr buf;
  2686. Variant ret;
  2687. if (SOAP_GLOBAL(sdl) && !SOAP_GLOBAL(sdl)->elements.empty() && data->name) {
  2688. string nscat;
  2689. if (data->ns && data->ns->href) {
  2690. nscat += (char*)data->ns->href;
  2691. nscat += ':';
  2692. }
  2693. nscat += (char*)data->name;
  2694. sdlTypeMap::const_iterator iter = SOAP_GLOBAL(sdl)->elements.find(nscat);
  2695. if (iter != SOAP_GLOBAL(sdl)->elements.end() && iter->second->encode) {
  2696. return master_to_zval_int(iter->second->encode, data);
  2697. }
  2698. }
  2699. buf = xmlBufferCreate();
  2700. xmlNodeDump(buf, nullptr, data, 0, 0);
  2701. ret = String((char*)xmlBufferContent(buf), CopyString);
  2702. xmlBufferFree(buf);
  2703. return ret;
  2704. }
  2705. static xmlNodePtr to_xml_any(encodeType* /*type*/, const Variant& data,
  2706. int style, xmlNodePtr parent) {
  2707. xmlNodePtr ret = nullptr;
  2708. if (data.isArray()) {
  2709. encodePtr enc = get_conversion(XSD_ANYXML);
  2710. Array arr = data.toArray();
  2711. for (ArrayIter iter(arr); iter; ++iter) {
  2712. ret = master_to_xml(enc, iter.second(), style, parent);
  2713. if (ret && ret->name != xmlStringTextNoenc &&
  2714. iter.first().isString()) {
  2715. xmlNodeSetName(ret, BAD_CAST(iter.first().toString().data()));
  2716. }
  2717. }
  2718. return ret;
  2719. }
  2720. String sdata = data.toString();
  2721. ret = xmlNewTextLen(BAD_CAST(sdata.data()), sdata.size());
  2722. ret->name = xmlStringTextNoenc;
  2723. ret->parent = parent;
  2724. ret->doc = parent->doc;
  2725. ret->prev = parent->last;
  2726. ret->next = nullptr;
  2727. if (parent->last) {
  2728. parent->last->next = ret;
  2729. } else {
  2730. parent->children = ret;
  2731. }
  2732. parent->last = ret;
  2733. return ret;
  2734. }
  2735. Variant sdl_guess_convert_zval(encodeType* enc, xmlNodePtr data) {
  2736. sdlType *type;
  2737. type = enc->sdl_type;
  2738. if (type == nullptr) {
  2739. return guess_zval_convert(enc, data);
  2740. }
  2741. /*FIXME: restriction support
  2742. if (type && type->restrictions &&
  2743. data && data->children && data->children->content) {
  2744. if (type->restrictions->whiteSpace && type->restrictions->whiteSpace->value) {
  2745. if (strcmp(type->restrictions->whiteSpace->value,"replace") == 0) {
  2746. whiteSpace_replace(data->children->content);
  2747. } else if (strcmp(type->restrictions->whiteSpace->value,"collapse") == 0) {
  2748. whiteSpace_collapse(data->children->content);
  2749. }
  2750. }
  2751. if (type->restrictions->enumeration) {
  2752. if (!zend_hash_exists(type->restrictions->enumeration,data->children->content,strlen(data->children->content)+1)) {
  2753. soap_error1(E_WARNING, "Encoding: Restriction: invalid enumeration value \"%s\"", data->children->content);
  2754. }
  2755. }
  2756. if (type->restrictions->minLength &&
  2757. strlen(data->children->content) < type->restrictions->minLength->value) {
  2758. soap_error0(E_WARNING, "Encoding: Restriction: length less than 'minLength'");
  2759. }
  2760. if (type->restrictions->maxLength &&
  2761. strlen(data->children->content) > type->restrictions->maxLength->value) {
  2762. soap_error0(E_WARNING, "Encoding: Restriction: length greater than 'maxLength'");
  2763. }
  2764. if (type->restrictions->length &&
  2765. strlen(data->children->content) != type->restrictions->length->value) {
  2766. soap_error0(E_WARNING, "Encoding: Restriction: length is not equal to 'length'");
  2767. }
  2768. }
  2769. */
  2770. switch (type->kind) {
  2771. case XSD_TYPEKIND_SIMPLE:
  2772. if (type->encode && enc != &type->encode->details) {
  2773. return master_to_zval_int(type->encode, data);
  2774. } else {
  2775. return guess_zval_convert(enc, data);
  2776. }
  2777. break;
  2778. case XSD_TYPEKIND_LIST:
  2779. return to_zval_list(enc, data);
  2780. case XSD_TYPEKIND_UNION:
  2781. return to_zval_union(enc, data);
  2782. case XSD_TYPEKIND_COMPLEX:
  2783. case XSD_TYPEKIND_RESTRICTION:
  2784. case XSD_TYPEKIND_EXTENSION:
  2785. if (type->encode && isSoapArrayType(type->encode->details.type)) {
  2786. return to_zval_array(enc, data);
  2787. }
  2788. return to_zval_object(enc, data);
  2789. default:
  2790. throw SoapException("Encoding: Internal Error");
  2791. }
  2792. return guess_zval_convert(enc, data);
  2793. }
  2794. xmlNodePtr sdl_guess_convert_xml(encodeType* enc, const Variant& data,
  2795. int style, xmlNodePtr parent) {
  2796. sdlType *type;
  2797. xmlNodePtr ret = nullptr;
  2798. type = enc->sdl_type;
  2799. if (type == nullptr) {
  2800. ret = guess_xml_convert(enc, data, style, parent);
  2801. if (style == SOAP_ENCODED) {
  2802. set_ns_and_type(ret, enc);
  2803. }
  2804. return ret;
  2805. }
  2806. /*FIXME: restriction support
  2807. if (type) {
  2808. if (type->restrictions && Z_TYPE_P(data) == IS_STRING) {
  2809. if (type->restrictions->enumeration) {
  2810. if (!zend_hash_exists(type->restrictions->enumeration,Z_STRVAL_P(data),Z_STRLEN_P(data)+1)) {
  2811. soap_error1(E_WARNING, "Encoding: Restriction: invalid enumeration value \"%s\".", Z_STRVAL_P(data));
  2812. }
  2813. }
  2814. if (type->restrictions->minLength &&
  2815. Z_STRLEN_P(data) < type->restrictions->minLength->value) {
  2816. soap_error0(E_WARNING, "Encoding: Restriction: length less than 'minLength'");
  2817. }
  2818. if (type->restrictions->maxLength &&
  2819. Z_STRLEN_P(data) > type->restrictions->maxLength->value) {
  2820. soap_error0(E_WARNING, "Encoding: Restriction: length greater than 'maxLength'");
  2821. }
  2822. if (type->restrictions->length &&
  2823. Z_STRLEN_P(data) != type->restrictions->length->value) {
  2824. soap_error0(E_WARNING, "Encoding: Restriction: length is not equal to 'length'");
  2825. }
  2826. }
  2827. }
  2828. */
  2829. switch(type->kind) {
  2830. case XSD_TYPEKIND_SIMPLE:
  2831. if (type->encode && enc != &type->encode->details) {
  2832. ret = master_to_xml(type->encode, data, style, parent);
  2833. } else {
  2834. ret = guess_xml_convert(enc, data, style, parent);
  2835. }
  2836. break;
  2837. case XSD_TYPEKIND_LIST:
  2838. ret = to_xml_list(enc, data, style, parent);
  2839. break;
  2840. case XSD_TYPEKIND_UNION:
  2841. ret = to_xml_union(enc, data, style, parent);
  2842. break;
  2843. case XSD_TYPEKIND_COMPLEX:
  2844. case XSD_TYPEKIND_RESTRICTION:
  2845. case XSD_TYPEKIND_EXTENSION:
  2846. if (type->encode && isSoapArrayType(type->encode->details.type)) {
  2847. return to_xml_array(enc, data, style, parent);
  2848. } else {
  2849. return to_xml_object(enc, data, style, parent);
  2850. }
  2851. break;
  2852. default:
  2853. throw SoapException("Encoding: Internal Error");
  2854. break;
  2855. }
  2856. if (style == SOAP_ENCODED) {
  2857. set_ns_and_type(ret, enc);
  2858. }
  2859. return ret;
  2860. }
  2861. static xmlNodePtr check_and_resolve_href(xmlNodePtr data) {
  2862. if (data && data->properties) {
  2863. xmlAttrPtr href;
  2864. href = data->properties;
  2865. while (1) {
  2866. href = get_attribute(href, "href");
  2867. if (href == nullptr || href->ns == nullptr) {break;}
  2868. href = href->next;
  2869. }
  2870. if (href) {
  2871. /* Internal href try and find node */
  2872. if (href->children->content[0] == '#') {
  2873. xmlNodePtr ret = get_node_with_attribute_recursive
  2874. (data->doc->children, nullptr, "id",
  2875. (char*)&href->children->content[1]);
  2876. if (!ret) {
  2877. throw SoapException("Encoding: Unresolved reference '%s'",
  2878. href->children->content);
  2879. }
  2880. return ret;
  2881. } else {
  2882. /* TODO: External href....? */
  2883. throw SoapException("Encoding: External reference '%s'",
  2884. href->children->content);
  2885. }
  2886. }
  2887. /* SOAP 1.2 enc:id enc:ref */
  2888. href = get_attribute_ex(data->properties, "ref", SOAP_1_2_ENC_NAMESPACE);
  2889. if (href) {
  2890. xmlChar* id;
  2891. xmlNodePtr ret;
  2892. if (href->children->content[0] == '#') {
  2893. id = href->children->content+1;
  2894. } else {
  2895. id = href->children->content;
  2896. }
  2897. ret = get_node_with_attribute_recursive_ex
  2898. (data->doc->children, nullptr, nullptr, "id", (char*)id,
  2899. SOAP_1_2_ENC_NAMESPACE);
  2900. if (!ret) {
  2901. throw SoapException("Encoding: Unresolved reference '%s'",
  2902. href->children->content);
  2903. } else if (ret == data) {
  2904. throw SoapException("Encoding: Violation of id and ref information "
  2905. "items '%s'", href->children->content);
  2906. }
  2907. return ret;
  2908. }
  2909. }
  2910. return data;
  2911. }
  2912. static void set_ns_and_type(xmlNodePtr node, encodeType* type) {
  2913. set_ns_and_type_ex(node, type->ns.c_str(), type->type_str.c_str());
  2914. }
  2915. static void set_ns_and_type_ex(xmlNodePtr node, const char *ns,
  2916. const char *type) {
  2917. string nstype;
  2918. get_type_str(node, ns, type, nstype);
  2919. set_xsi_type(node, nstype.c_str());
  2920. }
  2921. static xmlNsPtr xmlSearchNsPrefixByHref(xmlDocPtr doc, xmlNodePtr node,
  2922. const xmlChar * href) {
  2923. xmlNsPtr cur;
  2924. xmlNodePtr orig = node;
  2925. while (node) {
  2926. if (node->type == XML_ENTITY_REF_NODE ||
  2927. node->type == XML_ENTITY_NODE ||
  2928. node->type == XML_ENTITY_DECL) {
  2929. return nullptr;
  2930. }
  2931. if (node->type == XML_ELEMENT_NODE) {
  2932. cur = node->nsDef;
  2933. while (cur != nullptr) {
  2934. if (cur->prefix && cur->href && xmlStrEqual(cur->href, href)) {
  2935. if (xmlSearchNs(doc, node, cur->prefix) == cur) {
  2936. return cur;
  2937. }
  2938. }
  2939. cur = cur->next;
  2940. }
  2941. if (orig != node) {
  2942. cur = node->ns;
  2943. if (cur != nullptr) {
  2944. if (cur->prefix && cur->href && xmlStrEqual(cur->href, href)) {
  2945. if (xmlSearchNs(doc, node, cur->prefix) == cur) {
  2946. return cur;
  2947. }
  2948. }
  2949. }
  2950. }
  2951. }
  2952. node = node->parent;
  2953. }
  2954. return nullptr;
  2955. }
  2956. xmlNsPtr encode_add_ns(xmlNodePtr node, const char* ns) {
  2957. USE_SOAP_GLOBAL;
  2958. xmlNsPtr xmlns;
  2959. if (ns == nullptr || ns[0] == '\0') {
  2960. return nullptr;
  2961. }
  2962. xmlns = xmlSearchNsByHref(node->doc, node, BAD_CAST(ns));
  2963. if (xmlns != nullptr && xmlns->prefix == nullptr) {
  2964. xmlns = xmlSearchNsPrefixByHref(node->doc, node, BAD_CAST(ns));
  2965. }
  2966. if (xmlns == nullptr) {
  2967. std::map<string, string>::const_iterator iter =
  2968. SOAP_GLOBAL(defEncNs).find(ns);
  2969. if (iter != SOAP_GLOBAL(defEncNs).end()) {
  2970. xmlns = xmlNewNs(node->doc->children, BAD_CAST(ns),
  2971. (xmlChar*)iter->second.c_str());
  2972. } else {
  2973. int num = ++SOAP_GLOBAL(cur_uniq_ns);
  2974. string prefix;
  2975. while (1) {
  2976. prefix = "ns";
  2977. prefix += folly::to<string>(num);
  2978. if (xmlSearchNs(node->doc, node, BAD_CAST(prefix.c_str())) == nullptr) {
  2979. break;
  2980. }
  2981. num = ++SOAP_GLOBAL(cur_uniq_ns);
  2982. }
  2983. xmlns = xmlNewNs(node->doc->children, BAD_CAST(ns),
  2984. BAD_CAST(prefix.c_str()));
  2985. }
  2986. }
  2987. return xmlns;
  2988. }
  2989. static void set_ns_prop(xmlNodePtr node, const char *ns, const char *name,
  2990. const char *val) {
  2991. xmlSetNsProp(node, encode_add_ns(node, ns), BAD_CAST(name), BAD_CAST(val));
  2992. }
  2993. static void set_xsi_nil(xmlNodePtr node) {
  2994. set_ns_prop(node, XSI_NAMESPACE, "nil", "true");
  2995. }
  2996. static void set_xsi_type(xmlNodePtr node, const char *type) {
  2997. set_ns_prop(node, XSI_NAMESPACE, "type", type);
  2998. }
  2999. void encode_reset_ns() {
  3000. USE_SOAP_GLOBAL;
  3001. SOAP_GLOBAL(cur_uniq_ns) = 0;
  3002. SOAP_GLOBAL(cur_uniq_ref) = 0;
  3003. SOAP_GLOBAL(ref_map).clear();
  3004. SOAP_GLOBAL(node_map).clear();
  3005. }
  3006. void encode_finish() {
  3007. USE_SOAP_GLOBAL;
  3008. SOAP_GLOBAL(cur_uniq_ns) = 0;
  3009. SOAP_GLOBAL(cur_uniq_ref) = 0;
  3010. SOAP_GLOBAL(ref_map).clear();
  3011. SOAP_GLOBAL(node_map).clear();
  3012. }
  3013. encodePtr get_conversion(int encode) {
  3014. USE_SOAP_GLOBAL;
  3015. std::map<int, encodePtr>::const_iterator iter =
  3016. SOAP_GLOBAL(defEncIndex).find(encode);
  3017. if (iter != SOAP_GLOBAL(defEncIndex).end()) {
  3018. return iter->second;
  3019. }
  3020. throw SoapException( "Encoding: Cannot find encoding");
  3021. }
  3022. static encodePtr get_array_type(xmlNodePtr node, const Variant& array,
  3023. string &type) {
  3024. USE_SOAP_GLOBAL;
  3025. int i, count, cur_type, prev_type;
  3026. bool different;
  3027. const char *prev_stype = nullptr, *cur_stype = nullptr, *prev_ns = nullptr,
  3028. *cur_ns = nullptr;
  3029. if (!array.isArray()) {
  3030. type += "xsd:anyType";
  3031. return get_conversion(XSD_ANYTYPE);
  3032. }
  3033. Array ht = array.toArray();
  3034. different = false;
  3035. cur_type = prev_type = 0;
  3036. count = ht.size();
  3037. ArrayIter iter(ht);
  3038. for (i = 0;i < count;i++) {
  3039. Variant tmp = iter.second();
  3040. if (tmp.isObject() && tmp.toObject().instanceof(SoapVar::getClass())) {
  3041. auto svobj = tmp.toObject().get();
  3042. cur_type = SoapVar::getEncType(svobj);
  3043. auto enc_stype = SoapVar::getEncSType(svobj);
  3044. if (!enc_stype.empty()) {
  3045. cur_stype = enc_stype.c_str();
  3046. } else {
  3047. cur_stype = nullptr;
  3048. }
  3049. auto enc_ns = SoapVar::getEncNS(svobj);
  3050. if (!enc_ns.empty()) {
  3051. cur_ns = enc_ns.c_str();
  3052. } else {
  3053. cur_ns = nullptr;
  3054. }
  3055. } else if (tmp.isArray() && !tmp.toArray()->isVectorData()) {
  3056. cur_type = APACHE_MAP;
  3057. cur_stype = nullptr;
  3058. cur_ns = nullptr;
  3059. } else {
  3060. cur_type = dataTypeToSoap(tmp.getType());
  3061. cur_stype = nullptr;
  3062. cur_ns = nullptr;
  3063. }
  3064. if (i > 0) {
  3065. if ((cur_type != prev_type) ||
  3066. (cur_stype && prev_stype &&
  3067. strcmp(cur_stype,prev_stype) != 0) ||
  3068. (!cur_stype && cur_stype != prev_stype) ||
  3069. (cur_ns && prev_ns && strcmp(cur_ns,prev_ns)) ||
  3070. (!cur_ns && cur_ns != prev_ns)) {
  3071. different = true;
  3072. break;
  3073. }
  3074. }
  3075. prev_type = cur_type;
  3076. prev_stype = cur_stype;
  3077. prev_ns = cur_ns;
  3078. ++iter;
  3079. }
  3080. if (different || count == 0) {
  3081. type += "xsd:anyType";
  3082. return get_conversion(XSD_ANYTYPE);
  3083. }
  3084. encodePtr enc;
  3085. if (cur_stype) {
  3086. string array_type;
  3087. if (cur_ns) {
  3088. xmlNsPtr ns = encode_add_ns(node,cur_ns);
  3089. type += (char*)ns->prefix;
  3090. type += ':';
  3091. array_type += cur_ns;
  3092. array_type += ':';
  3093. }
  3094. type += cur_stype;
  3095. array_type += cur_stype;
  3096. enc = get_encoder_ex(SOAP_GLOBAL(sdl), array_type);
  3097. } else {
  3098. enc = get_conversion(cur_type);
  3099. get_type_str(node, enc->details.ns.c_str(),
  3100. enc->details.type_str.c_str(), type);
  3101. }
  3102. return enc;
  3103. }
  3104. static void get_type_str(xmlNodePtr node, const char* ns, const char* type,
  3105. string &ret) {
  3106. USE_SOAP_GLOBAL;
  3107. if (ns) {
  3108. xmlNsPtr xmlns;
  3109. if (SOAP_GLOBAL(soap_version) == SOAP_1_2 &&
  3110. strcmp(ns,SOAP_1_1_ENC_NAMESPACE) == 0) {
  3111. ns = SOAP_1_2_ENC_NAMESPACE;
  3112. } else if (SOAP_GLOBAL(soap_version) == SOAP_1_1 &&
  3113. strcmp(ns,SOAP_1_2_ENC_NAMESPACE) == 0) {
  3114. ns = SOAP_1_1_ENC_NAMESPACE;
  3115. }
  3116. xmlns = encode_add_ns(node,ns);
  3117. ret += (char*)xmlns->prefix;
  3118. ret += ':';
  3119. }
  3120. ret += type;
  3121. }
  3122. ///////////////////////////////////////////////////////////////////////////////
  3123. }