PageRenderTime 62ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/editor/tinymce/plugins/spellchecker/classes/utils/JSON.php

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