PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/ext/json/ext_json.cpp

https://github.com/tstarling/hiphop-php
C++ | 257 lines | 202 code | 27 blank | 28 comment | 29 complexity | 51cf435c5eda60632ea04d9629eaa9f1 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 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/json/ext_json.h"
  18. #include "hphp/runtime/ext/json/JSON_parser.h"
  19. #include "hphp/runtime/base/utf8-decode.h"
  20. #include "hphp/runtime/base/variable-serializer.h"
  21. namespace HPHP {
  22. ///////////////////////////////////////////////////////////////////////////////
  23. // json_encode() options
  24. const int64_t k_JSON_HEX_TAG = 1<<0;
  25. const int64_t k_JSON_HEX_AMP = 1<<1;
  26. const int64_t k_JSON_HEX_APOS = 1<<2;
  27. const int64_t k_JSON_HEX_QUOT = 1<<3;
  28. const int64_t k_JSON_FORCE_OBJECT = 1<<4;
  29. const int64_t k_JSON_NUMERIC_CHECK = 1<<5;
  30. const int64_t k_JSON_UNESCAPED_SLASHES = 1<<6;
  31. const int64_t k_JSON_PRETTY_PRINT = 1<<7;
  32. const int64_t k_JSON_UNESCAPED_UNICODE = 1<<8;
  33. // json_decode() options
  34. const int64_t k_JSON_BIGINT_AS_STRING = 1<<0;
  35. // FB json_decode() options
  36. // intentionally higher so when PHP adds more options we're fine
  37. const int64_t k_JSON_FB_LOOSE = 1<<20;
  38. const int64_t k_JSON_FB_UNLIMITED = 1<<21;
  39. const int64_t k_JSON_FB_EXTRA_ESCAPES = 1<<22;
  40. const int64_t k_JSON_FB_COLLECTIONS = 1<<23;
  41. const int64_t k_JSON_FB_STABLE_MAPS = 1<<24;
  42. const int64_t k_JSON_ERROR_NONE
  43. = json_error_codes::JSON_ERROR_NONE;
  44. const int64_t k_JSON_ERROR_DEPTH
  45. = json_error_codes::JSON_ERROR_DEPTH;
  46. const int64_t k_JSON_ERROR_STATE_MISMATCH
  47. = json_error_codes::JSON_ERROR_STATE_MISMATCH;
  48. const int64_t k_JSON_ERROR_CTRL_CHAR
  49. = json_error_codes::JSON_ERROR_CTRL_CHAR;
  50. const int64_t k_JSON_ERROR_SYNTAX
  51. = json_error_codes::JSON_ERROR_SYNTAX;
  52. const int64_t k_JSON_ERROR_UTF8
  53. = json_error_codes::JSON_ERROR_UTF8;
  54. ///////////////////////////////////////////////////////////////////////////////
  55. int64_t HHVM_FUNCTION(json_last_error) {
  56. return (int) json_get_last_error_code();
  57. }
  58. String HHVM_FUNCTION(json_last_error_msg) {
  59. return json_get_last_error_msg();
  60. }
  61. String HHVM_FUNCTION(json_encode, const Variant& value, int64_t options /* = 0 */,
  62. int64_t depth /* = 512 */) {
  63. json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
  64. VariableSerializer vs(VariableSerializer::Type::JSON, options);
  65. return vs.serializeValue(value, !(options & k_JSON_FB_UNLIMITED));
  66. }
  67. Variant HHVM_FUNCTION(json_decode, const String& json, bool assoc /* = false */,
  68. int64_t depth /* = 512 */, int64_t options /* = 0 */) {
  69. json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
  70. if (json.empty()) {
  71. return uninit_null();
  72. }
  73. const int64_t supported_options =
  74. k_JSON_FB_LOOSE |
  75. k_JSON_FB_COLLECTIONS |
  76. k_JSON_FB_STABLE_MAPS |
  77. k_JSON_BIGINT_AS_STRING;
  78. int64_t parser_options = options & supported_options;
  79. Variant z;
  80. if (JSON_parser(z, json.data(), json.size(), assoc, depth, parser_options)) {
  81. return z;
  82. }
  83. if (json.size() == 4) {
  84. if (!strcasecmp(json.data(), "null")) {
  85. json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
  86. return uninit_null();
  87. }
  88. if (!strcasecmp(json.data(), "true")) {
  89. json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
  90. return true;
  91. }
  92. } else if (json.size() == 5 && !strcasecmp(json.data(), "false")) {
  93. json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
  94. return false;
  95. }
  96. int64_t p;
  97. double d;
  98. DataType type = json.get()->isNumericWithVal(p, d, 0);
  99. if (type == KindOfInt64) {
  100. json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
  101. return p;
  102. } else if (type == KindOfDouble) {
  103. json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
  104. return d;
  105. }
  106. char ch0 = json.charAt(0);
  107. if (json.size() > 1 && ch0 == '"' && json.charAt(json.size() - 1) == '"') {
  108. json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
  109. // Wrap the string in an array to allow the JSON_parser to handle
  110. // things like unicode escape sequences, then unwrap to get result
  111. String wrapped("[");
  112. wrapped += json + "]";
  113. // Stick to a normal hhvm array for the wrapper
  114. const int64_t mask = ~(k_JSON_FB_COLLECTIONS | k_JSON_FB_STABLE_MAPS);
  115. if (JSON_parser(z, wrapped.data(), wrapped.size(), false, depth,
  116. parser_options & mask) && z.isArray()) {
  117. Array arr = z.toArray();
  118. if ((arr.size() == 1) && arr.exists(0)) {
  119. return arr[0];
  120. }
  121. // The input string could be something like: "foo","bar"
  122. // Which will parse inside the [] wrapper, but be invalid
  123. json_set_last_error_code(json_error_codes::JSON_ERROR_SYNTAX);
  124. }
  125. }
  126. if ((options & k_JSON_FB_LOOSE) && json.size() > 1 &&
  127. ch0 == '\'' && json.charAt(json.size() - 1) == '\'') {
  128. json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
  129. return json.substr(1, json.size() - 2);
  130. }
  131. assert(json_get_last_error_code() != json_error_codes::JSON_ERROR_NONE);
  132. return uninit_null();
  133. }
  134. ///////////////////////////////////////////////////////////////////////////////
  135. const StaticString s_JSON_HEX_TAG("JSON_HEX_TAG");
  136. const StaticString s_JSON_HEX_AMP("JSON_HEX_AMP");
  137. const StaticString s_JSON_HEX_APOS("JSON_HEX_APOS");
  138. const StaticString s_JSON_HEX_QUOT("JSON_HEX_QUOT");
  139. const StaticString s_JSON_FORCE_OBJECT("JSON_FORCE_OBJECT");
  140. const StaticString s_JSON_NUMERIC_CHECK("JSON_NUMERIC_CHECK");
  141. const StaticString s_JSON_UNESCAPED_SLASHES("JSON_UNESCAPED_SLASHES");
  142. const StaticString s_JSON_PRETTY_PRINT("JSON_PRETTY_PRINT");
  143. const StaticString s_JSON_UNESCAPED_UNICODE("JSON_UNESCAPED_UNICODE");
  144. const StaticString s_JSON_BIGINT_AS_STRING("JSON_BIGINT_AS_STRING");
  145. const StaticString s_JSON_FB_LOOSE("JSON_FB_LOOSE");
  146. const StaticString s_JSON_FB_UNLIMITED("JSON_FB_UNLIMITED");
  147. const StaticString s_JSON_FB_EXTRA_ESCAPES("JSON_FB_EXTRA_ESCAPES");
  148. const StaticString s_JSON_FB_COLLECTIONS("JSON_FB_COLLECTIONS");
  149. const StaticString s_JSON_FB_STABLE_MAPS("JSON_FB_STABLE_MAPS");
  150. const StaticString s_JSON_ERROR_NONE("JSON_ERROR_NONE");
  151. const StaticString s_JSON_ERROR_DEPTH("JSON_ERROR_DEPTH");
  152. const StaticString s_JSON_ERROR_STATE_MISMATCH("JSON_ERROR_STATE_MISMATCH");
  153. const StaticString s_JSON_ERROR_CTRL_CHAR("JSON_ERROR_CTRL_CHAR");
  154. const StaticString s_JSON_ERROR_SYNTAX("JSON_ERROR_SYNTAX");
  155. const StaticString s_JSON_ERROR_UTF8("JSON_ERROR_UTF8");
  156. class JsonExtension : public Extension {
  157. public:
  158. JsonExtension() : Extension("json", "1.2.1") {}
  159. virtual void moduleInit() {
  160. Native::registerConstant<KindOfInt64>(
  161. s_JSON_HEX_TAG.get(), k_JSON_HEX_TAG
  162. );
  163. Native::registerConstant<KindOfInt64>(
  164. s_JSON_HEX_AMP.get(), k_JSON_HEX_AMP
  165. );
  166. Native::registerConstant<KindOfInt64>(
  167. s_JSON_HEX_APOS.get(), k_JSON_HEX_APOS
  168. );
  169. Native::registerConstant<KindOfInt64>(
  170. s_JSON_HEX_QUOT.get(), k_JSON_HEX_QUOT
  171. );
  172. Native::registerConstant<KindOfInt64>(
  173. s_JSON_FORCE_OBJECT.get(), k_JSON_FORCE_OBJECT
  174. );
  175. Native::registerConstant<KindOfInt64>(
  176. s_JSON_NUMERIC_CHECK.get(), k_JSON_NUMERIC_CHECK
  177. );
  178. Native::registerConstant<KindOfInt64>(
  179. s_JSON_UNESCAPED_SLASHES.get(), k_JSON_UNESCAPED_SLASHES
  180. );
  181. Native::registerConstant<KindOfInt64>(
  182. s_JSON_PRETTY_PRINT.get(), k_JSON_PRETTY_PRINT
  183. );
  184. Native::registerConstant<KindOfInt64>(
  185. s_JSON_UNESCAPED_UNICODE.get(), k_JSON_UNESCAPED_UNICODE
  186. );
  187. Native::registerConstant<KindOfInt64>(
  188. s_JSON_BIGINT_AS_STRING.get(), k_JSON_BIGINT_AS_STRING
  189. );
  190. Native::registerConstant<KindOfInt64>(
  191. s_JSON_FB_LOOSE.get(), k_JSON_FB_LOOSE
  192. );
  193. Native::registerConstant<KindOfInt64>(
  194. s_JSON_FB_UNLIMITED.get(), k_JSON_FB_UNLIMITED
  195. );
  196. Native::registerConstant<KindOfInt64>(
  197. s_JSON_FB_EXTRA_ESCAPES.get(), k_JSON_FB_EXTRA_ESCAPES
  198. );
  199. Native::registerConstant<KindOfInt64>(
  200. s_JSON_FB_COLLECTIONS.get(), k_JSON_FB_COLLECTIONS
  201. );
  202. Native::registerConstant<KindOfInt64>(
  203. s_JSON_FB_STABLE_MAPS.get(), k_JSON_FB_STABLE_MAPS
  204. );
  205. Native::registerConstant<KindOfInt64>(
  206. s_JSON_ERROR_NONE.get(), k_JSON_ERROR_NONE
  207. );
  208. Native::registerConstant<KindOfInt64>(
  209. s_JSON_ERROR_DEPTH.get(), k_JSON_ERROR_DEPTH
  210. );
  211. Native::registerConstant<KindOfInt64>(
  212. s_JSON_ERROR_STATE_MISMATCH.get(), k_JSON_ERROR_STATE_MISMATCH
  213. );
  214. Native::registerConstant<KindOfInt64>(
  215. s_JSON_ERROR_CTRL_CHAR.get(), k_JSON_ERROR_CTRL_CHAR
  216. );
  217. Native::registerConstant<KindOfInt64>(
  218. s_JSON_ERROR_SYNTAX.get(), k_JSON_ERROR_SYNTAX
  219. );
  220. Native::registerConstant<KindOfInt64>(
  221. s_JSON_ERROR_UTF8.get(), k_JSON_ERROR_UTF8
  222. );
  223. HHVM_FE(json_last_error);
  224. HHVM_FE(json_last_error_msg);
  225. HHVM_FE(json_encode);
  226. HHVM_FE(json_decode);
  227. loadSystemlib();
  228. }
  229. } s_json_extension;
  230. }