PageRenderTime 39ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/JSON.php

https://bitbucket.org/crypticrod/sr_wp_code
PHP | 595 lines | 520 code | 63 blank | 12 comment | 32 complexity | 37d66b8bfeed6464ebfa430c6244f159 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, LGPL-2.1, GPL-3.0, LGPL-2.0, AGPL-3.0
  1. <?php
  2. /**
  3. * $Id: JSON.php 40 2007-06-18 11:43:15Z spocke $
  4. *
  5. * @package MCManager.utils
  6. * @author Moxiecode
  7. * @copyright Copyright © 2007, Moxiecode Systems AB, All rights reserved.
  8. */
  9. define('JSON_BOOL', 1);
  10. define('JSON_INT', 2);
  11. define('JSON_STR', 3);
  12. define('JSON_FLOAT', 4);
  13. define('JSON_NULL', 5);
  14. define('JSON_START_OBJ', 6);
  15. define('JSON_END_OBJ', 7);
  16. define('JSON_START_ARRAY', 8);
  17. define('JSON_END_ARRAY', 9);
  18. define('JSON_KEY', 10);
  19. define('JSON_SKIP', 11);
  20. define('JSON_IN_ARRAY', 30);
  21. define('JSON_IN_OBJECT', 40);
  22. define('JSON_IN_BETWEEN', 50);
  23. class Moxiecode_JSONReader {
  24. var $_data, $_len, $_pos;
  25. var $_value, $_token;
  26. var $_location, $_lastLocations;
  27. var $_needProp;
  28. function Moxiecode_JSONReader($data) {
  29. $this->_data = $data;
  30. $this->_len = strlen($data);
  31. $this->_pos = -1;
  32. $this->_location = JSON_IN_BETWEEN;
  33. $this->_lastLocations = array();
  34. $this->_needProp = false;
  35. }
  36. function getToken() {
  37. return $this->_token;
  38. }
  39. function getLocation() {
  40. return $this->_location;
  41. }
  42. function getTokenName() {
  43. switch ($this->_token) {
  44. case JSON_BOOL:
  45. return 'JSON_BOOL';
  46. case JSON_INT:
  47. return 'JSON_INT';
  48. case JSON_STR:
  49. return 'JSON_STR';
  50. case JSON_FLOAT:
  51. return 'JSON_FLOAT';
  52. case JSON_NULL:
  53. return 'JSON_NULL';
  54. case JSON_START_OBJ:
  55. return 'JSON_START_OBJ';
  56. case JSON_END_OBJ:
  57. return 'JSON_END_OBJ';
  58. case JSON_START_ARRAY:
  59. return 'JSON_START_ARRAY';
  60. case JSON_END_ARRAY:
  61. return 'JSON_END_ARRAY';
  62. case JSON_KEY:
  63. return 'JSON_KEY';
  64. }
  65. return 'UNKNOWN';
  66. }
  67. function getValue() {
  68. return $this->_value;
  69. }
  70. function readToken() {
  71. $chr = $this->read();
  72. if ($chr != null) {
  73. switch ($chr) {
  74. case '[':
  75. $this->_lastLocation[] = $this->_location;
  76. $this->_location = JSON_IN_ARRAY;
  77. $this->_token = JSON_START_ARRAY;
  78. $this->_value = null;
  79. $this->readAway();
  80. return true;
  81. case ']':
  82. $this->_location = array_pop($this->_lastLocation);
  83. $this->_token = JSON_END_ARRAY;
  84. $this->_value = null;
  85. $this->readAway();
  86. if ($this->_location == JSON_IN_OBJECT)
  87. $this->_needProp = true;
  88. return true;
  89. case '{':
  90. $this->_lastLocation[] = $this->_location;
  91. $this->_location = JSON_IN_OBJECT;
  92. $this->_needProp = true;
  93. $this->_token = JSON_START_OBJ;
  94. $this->_value = null;
  95. $this->readAway();
  96. return true;
  97. case '}':
  98. $this->_location = array_pop($this->_lastLocation);
  99. $this->_token = JSON_END_OBJ;
  100. $this->_value = null;
  101. $this->readAway();
  102. if ($this->_location == JSON_IN_OBJECT)
  103. $this->_needProp = true;
  104. return true;
  105. // String
  106. case '"':
  107. case '\'':
  108. return $this->_readString($chr);
  109. // Null
  110. case 'n':
  111. return $this->_readNull();
  112. // Bool
  113. case 't':
  114. case 'f':
  115. return $this->_readBool($chr);
  116. default:
  117. // Is number
  118. if (is_numeric($chr) || $chr == '-' || $chr == '.')
  119. return $this->_readNumber($chr);
  120. return true;
  121. }
  122. }
  123. return false;
  124. }
  125. function _readBool($chr) {
  126. $this->_token = JSON_BOOL;
  127. $this->_value = $chr == 't';
  128. if ($chr == 't')
  129. $this->skip(3); // rue
  130. else
  131. $this->skip(4); // alse
  132. $this->readAway();
  133. if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
  134. $this->_needProp = true;
  135. return true;
  136. }
  137. function _readNull() {
  138. $this->_token = JSON_NULL;
  139. $this->_value = null;
  140. $this->skip(3); // ull
  141. $this->readAway();
  142. if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
  143. $this->_needProp = true;
  144. return true;
  145. }
  146. function _readString($quote) {
  147. $output = "";
  148. $this->_token = JSON_STR;
  149. $endString = false;
  150. while (($chr = $this->peek()) != -1) {
  151. switch ($chr) {
  152. case '\\':
  153. // Read away slash
  154. $this->read();
  155. // Read escape code
  156. $chr = $this->read();
  157. switch ($chr) {
  158. case 't':
  159. $output .= "\t";
  160. break;
  161. case 'b':
  162. $output .= "\b";
  163. break;
  164. case 'f':
  165. $output .= "\f";
  166. break;
  167. case 'r':
  168. $output .= "\r";
  169. break;
  170. case 'n':
  171. $output .= "\n";
  172. break;
  173. case 'u':
  174. $output .= $this->_int2utf8(hexdec($this->read(4)));
  175. break;
  176. default:
  177. $output .= $chr;
  178. break;
  179. }
  180. break;
  181. case '\'':
  182. case '"':
  183. if ($chr == $quote)
  184. $endString = true;
  185. $chr = $this->read();
  186. if ($chr != -1 && $chr != $quote)
  187. $output .= $chr;
  188. break;
  189. default:
  190. $output .= $this->read();
  191. }
  192. // String terminated
  193. if ($endString)
  194. break;
  195. }
  196. $this->readAway();
  197. $this->_value = $output;
  198. // Needed a property
  199. if ($this->_needProp) {
  200. $this->_token = JSON_KEY;
  201. $this->_needProp = false;
  202. return true;
  203. }
  204. if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
  205. $this->_needProp = true;
  206. return true;
  207. }
  208. function _int2utf8($int) {
  209. $int = intval($int);
  210. switch ($int) {
  211. case 0:
  212. return chr(0);
  213. case ($int & 0x7F):
  214. return chr($int);
  215. case ($int & 0x7FF):
  216. return chr(0xC0 | (($int >> 6) & 0x1F)) . chr(0x80 | ($int & 0x3F));
  217. case ($int & 0xFFFF):
  218. return chr(0xE0 | (($int >> 12) & 0x0F)) . chr(0x80 | (($int >> 6) & 0x3F)) . chr (0x80 | ($int & 0x3F));
  219. case ($int & 0x1FFFFF):
  220. return chr(0xF0 | ($int >> 18)) . chr(0x80 | (($int >> 12) & 0x3F)) . chr(0x80 | (($int >> 6) & 0x3F)) . chr(0x80 | ($int & 0x3F));
  221. }
  222. }
  223. function _readNumber($start) {
  224. $value = "";
  225. $isFloat = false;
  226. $this->_token = JSON_INT;
  227. $value .= $start;
  228. while (($chr = $this->peek()) != -1) {
  229. if (is_numeric($chr) || $chr == '-' || $chr == '.') {
  230. if ($chr == '.')
  231. $isFloat = true;
  232. $value .= $this->read();
  233. } else
  234. break;
  235. }
  236. $this->readAway();
  237. if ($isFloat) {
  238. $this->_token = JSON_FLOAT;
  239. $this->_value = floatval($value);
  240. } else
  241. $this->_value = intval($value);
  242. if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
  243. $this->_needProp = true;
  244. return true;
  245. }
  246. function readAway() {
  247. while (($chr = $this->peek()) != null) {
  248. if ($chr != ':' && $chr != ',' && $chr != ' ')
  249. return;
  250. $this->read();
  251. }
  252. }
  253. function read($len = 1) {
  254. if ($this->_pos < $this->_len) {
  255. if ($len > 1) {
  256. $str = substr($this->_data, $this->_pos + 1, $len);
  257. $this->_pos += $len;
  258. return $str;
  259. } else
  260. return $this->_data[++$this->_pos];
  261. }
  262. return null;
  263. }
  264. function skip($len) {
  265. $this->_pos += $len;
  266. }
  267. function peek() {
  268. if ($this->_pos < $this->_len)
  269. return $this->_data[$this->_pos + 1];
  270. return null;
  271. }
  272. }
  273. /**
  274. * This class handles JSON stuff.
  275. *
  276. * @package MCManager.utils
  277. */
  278. class Moxiecode_JSON {
  279. function Moxiecode_JSON() {
  280. }
  281. function decode($input) {
  282. $reader = new Moxiecode_JSONReader($input);
  283. return $this->readValue($reader);
  284. }
  285. function readValue(&$reader) {
  286. $this->data = array();
  287. $this->parents = array();
  288. $this->cur =& $this->data;
  289. $key = null;
  290. $loc = JSON_IN_ARRAY;
  291. while ($reader->readToken()) {
  292. switch ($reader->getToken()) {
  293. case JSON_STR:
  294. case JSON_INT:
  295. case JSON_BOOL:
  296. case JSON_FLOAT:
  297. case JSON_NULL:
  298. switch ($reader->getLocation()) {
  299. case JSON_IN_OBJECT:
  300. $this->cur[$key] = $reader->getValue();
  301. break;
  302. case JSON_IN_ARRAY:
  303. $this->cur[] = $reader->getValue();
  304. break;
  305. default:
  306. return $reader->getValue();
  307. }
  308. break;
  309. case JSON_KEY:
  310. $key = $reader->getValue();
  311. break;
  312. case JSON_START_OBJ:
  313. case JSON_START_ARRAY:
  314. if ($loc == JSON_IN_OBJECT)
  315. $this->addArray($key);
  316. else
  317. $this->addArray(null);
  318. $cur =& $obj;
  319. $loc = $reader->getLocation();
  320. break;
  321. case JSON_END_OBJ:
  322. case JSON_END_ARRAY:
  323. $loc = $reader->getLocation();
  324. if (count($this->parents) > 0) {
  325. $this->cur =& $this->parents[count($this->parents) - 1];
  326. array_pop($this->parents);
  327. }
  328. break;
  329. }
  330. }
  331. return $this->data[0];
  332. }
  333. // This method was needed since PHP is crapy and doesn't have pointers/references
  334. function addArray($key) {
  335. $this->parents[] =& $this->cur;
  336. $ar = array();
  337. if ($key)
  338. $this->cur[$key] =& $ar;
  339. else
  340. $this->cur[] =& $ar;
  341. $this->cur =& $ar;
  342. }
  343. function getDelim($index, &$reader) {
  344. switch ($reader->getLocation()) {
  345. case JSON_IN_ARRAY:
  346. case JSON_IN_OBJECT:
  347. if ($index > 0)
  348. return ",";
  349. break;
  350. }
  351. return "";
  352. }
  353. function encode($input) {
  354. switch (gettype($input)) {
  355. case 'boolean':
  356. return $input ? 'true' : 'false';
  357. case 'integer':
  358. return (int) $input;
  359. case 'float':
  360. case 'double':
  361. return (float) $input;
  362. case 'NULL':
  363. return 'null';
  364. case 'string':
  365. return $this->encodeString($input);
  366. case 'array':
  367. return $this->_encodeArray($input);
  368. case 'object':
  369. return $this->_encodeArray(get_object_vars($input));
  370. }
  371. return '';
  372. }
  373. function encodeString($input) {
  374. // Needs to be escaped
  375. if (preg_match('/[^a-zA-Z0-9]/', $input)) {
  376. $output = '';
  377. for ($i=0; $i<strlen($input); $i++) {
  378. switch ($input[$i]) {
  379. case "\b":
  380. $output .= "\\b";
  381. break;
  382. case "\t":
  383. $output .= "\\t";
  384. break;
  385. case "\f":
  386. $output .= "\\f";
  387. break;
  388. case "\r":
  389. $output .= "\\r";
  390. break;
  391. case "\n":
  392. $output .= "\\n";
  393. break;
  394. case '\\':
  395. $output .= "\\\\";
  396. break;
  397. case '\'':
  398. $output .= "\\'";
  399. break;
  400. case '"':
  401. $output .= '\"';
  402. break;
  403. default:
  404. $byte = ord($input[$i]);
  405. if (($byte & 0xE0) == 0xC0) {
  406. $char = pack('C*', $byte, ord($input[$i + 1]));
  407. $i += 1;
  408. $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
  409. } if (($byte & 0xF0) == 0xE0) {
  410. $char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]));
  411. $i += 2;
  412. $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
  413. } if (($byte & 0xF8) == 0xF0) {
  414. $char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]), ord($input[$i + 3]));
  415. $i += 3;
  416. $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
  417. } if (($byte & 0xFC) == 0xF8) {
  418. $char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]), ord($input[$i + 3]), ord($input[$i + 4]));
  419. $i += 4;
  420. $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
  421. } if (($byte & 0xFE) == 0xFC) {
  422. $char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]), ord($input[$i + 3]), ord($input[$i + 4]), ord($input[$i + 5]));
  423. $i += 5;
  424. $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
  425. } else if ($byte < 128)
  426. $output .= $input[$i];
  427. }
  428. }
  429. return '"' . $output . '"';
  430. }
  431. return '"' . $input . '"';
  432. }
  433. function _utf82utf16($utf8) {
  434. if (function_exists('mb_convert_encoding'))
  435. return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
  436. switch (strlen($utf8)) {
  437. case 1:
  438. return $utf8;
  439. case 2:
  440. return chr(0x07 & (ord($utf8[0]) >> 2)) . chr((0xC0 & (ord($utf8[0]) << 6)) | (0x3F & ord($utf8[1])));
  441. case 3:
  442. return chr((0xF0 & (ord($utf8[0]) << 4)) | (0x0F & (ord($utf8[1]) >> 2))) . chr((0xC0 & (ord($utf8[1]) << 6)) | (0x7F & ord($utf8[2])));
  443. }
  444. return '';
  445. }
  446. function _encodeArray($input) {
  447. $output = '';
  448. $isIndexed = true;
  449. $keys = array_keys($input);
  450. for ($i=0; $i<count($keys); $i++) {
  451. if (!is_int($keys[$i])) {
  452. $output .= $this->encodeString($keys[$i]) . ':' . $this->encode($input[$keys[$i]]);
  453. $isIndexed = false;
  454. } else
  455. $output .= $this->encode($input[$keys[$i]]);
  456. if ($i != count($keys) - 1)
  457. $output .= ',';
  458. }
  459. return $isIndexed ? '[' . $output . ']' : '{' . $output . '}';
  460. }
  461. }
  462. ?>