source: moodle/trunk/fuentes/lib/editor/tinymce/plugins/spellchecker/classes/utils/JSON.php @ 1331

Last change on this file since 1331 was 1331, checked in by jrpelegrina, 3 years ago

Updated to moodle 3.0.3

File size: 11.9 KB
Line 
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
10define('JSON_BOOL', 1);
11define('JSON_INT', 2);
12define('JSON_STR', 3);
13define('JSON_FLOAT', 4);
14define('JSON_NULL', 5);
15define('JSON_START_OBJ', 6);
16define('JSON_END_OBJ', 7);
17define('JSON_START_ARRAY', 8);
18define('JSON_END_ARRAY', 9);
19define('JSON_KEY', 10);
20define('JSON_SKIP', 11);
21
22define('JSON_IN_ARRAY', 30);
23define('JSON_IN_OBJECT', 40);
24define('JSON_IN_BETWEEN', 50);
25
26class Moxiecode_JSONReader {
27        var $_data, $_len, $_pos;
28        var $_value, $_token;
29        var $_location, $_lastLocations;
30        var $_needProp;
31
32        public function __construct($data) {
33                $this->_data = $data;
34                $this->_len = strlen($data);
35                $this->_pos = -1;
36                $this->_location = JSON_IN_BETWEEN;
37                $this->_lastLocations = array();
38                $this->_needProp = false;
39        }
40
41    /**
42     * Old syntax of class constructor. Deprecated in PHP7.
43     */
44    public function Moxiecode_JSONReader($data) {
45        self::__construct($data);
46    }
47
48        function getToken() {
49                return $this->_token;
50        }
51
52        function getLocation() {
53                return $this->_location;
54        }
55
56        function getTokenName() {
57                switch ($this->_token) {
58                        case JSON_BOOL:
59                                return 'JSON_BOOL';
60
61                        case JSON_INT:
62                                return 'JSON_INT';
63
64                        case JSON_STR:
65                                return 'JSON_STR';
66
67                        case JSON_FLOAT:
68                                return 'JSON_FLOAT';
69
70                        case JSON_NULL:
71                                return 'JSON_NULL';
72
73                        case JSON_START_OBJ:
74                                return 'JSON_START_OBJ';
75
76                        case JSON_END_OBJ:
77                                return 'JSON_END_OBJ';
78
79                        case JSON_START_ARRAY:
80                                return 'JSON_START_ARRAY';
81
82                        case JSON_END_ARRAY:
83                                return 'JSON_END_ARRAY';
84
85                        case JSON_KEY:
86                                return 'JSON_KEY';
87                }
88
89                return 'UNKNOWN';
90        }
91
92        function getValue() {
93                return $this->_value;
94        }
95
96        function readToken() {
97                $chr = $this->read();
98
99                if ($chr != null) {
100                        switch ($chr) {
101                                case '[':
102                                        $this->_lastLocation[] = $this->_location;
103                                        $this->_location = JSON_IN_ARRAY;
104                                        $this->_token = JSON_START_ARRAY;
105                                        $this->_value = null;
106                                        $this->readAway();
107                                        return true;
108
109                                case ']':
110                                        $this->_location = array_pop($this->_lastLocation);
111                                        $this->_token = JSON_END_ARRAY;
112                                        $this->_value = null;
113                                        $this->readAway();
114
115                                        if ($this->_location == JSON_IN_OBJECT)
116                                                $this->_needProp = true;
117
118                                        return true;
119
120                                case '{':
121                                        $this->_lastLocation[] = $this->_location;
122                                        $this->_location = JSON_IN_OBJECT;
123                                        $this->_needProp = true;
124                                        $this->_token = JSON_START_OBJ;
125                                        $this->_value = null;
126                                        $this->readAway();
127                                        return true;
128
129                                case '}':
130                                        $this->_location = array_pop($this->_lastLocation);
131                                        $this->_token = JSON_END_OBJ;
132                                        $this->_value = null;
133                                        $this->readAway();
134
135                                        if ($this->_location == JSON_IN_OBJECT)
136                                                $this->_needProp = true;
137
138                                        return true;
139
140                                // String
141                                case '"':
142                                case '\'':
143                                        return $this->_readString($chr);
144
145                                // Null
146                                case 'n':
147                                        return $this->_readNull();
148
149                                // Bool
150                                case 't':
151                                case 'f':
152                                        return $this->_readBool($chr);
153
154                                default:
155                                        // Is number
156                                        if (is_numeric($chr) || $chr == '-' || $chr == '.')
157                                                return $this->_readNumber($chr);
158
159                                        return true;
160                        }
161                }
162
163                return false;
164        }
165
166        function _readBool($chr) {
167                $this->_token = JSON_BOOL;
168                $this->_value = $chr == 't';
169
170                if ($chr == 't')
171                        $this->skip(3); // rue
172                else
173                        $this->skip(4); // alse
174
175                $this->readAway();
176
177                if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
178                        $this->_needProp = true;
179
180                return true;
181        }
182
183        function _readNull() {
184                $this->_token = JSON_NULL;
185                $this->_value = null;
186
187                $this->skip(3); // ull
188                $this->readAway();
189
190                if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
191                        $this->_needProp = true;
192
193                return true;
194        }
195
196        function _readString($quote) {
197                $output = "";
198                $this->_token = JSON_STR;
199                $endString = false;
200
201                while (($chr = $this->peek()) != -1) {
202                        switch ($chr) {
203                                case '\\':
204                                        // Read away slash
205                                        $this->read();
206
207                                        // Read escape code
208                                        $chr = $this->read();
209                                        switch ($chr) {
210                                                        case 't':
211                                                                $output .= "\t";
212                                                                break;
213
214                                                        case 'b':
215                                                                $output .= "\b";
216                                                                break;
217
218                                                        case 'f':
219                                                                $output .= "\f";
220                                                                break;
221
222                                                        case 'r':
223                                                                $output .= "\r";
224                                                                break;
225
226                                                        case 'n':
227                                                                $output .= "\n";
228                                                                break;
229
230                                                        case 'u':
231                                                                $output .= $this->_int2utf8(hexdec($this->read(4)));
232                                                                break;
233
234                                                        default:
235                                                                $output .= $chr;
236                                                                break;
237                                        }
238
239                                        break;
240
241                                        case '\'':
242                                        case '"':
243                                                if ($chr == $quote)
244                                                        $endString = true;
245
246                                                $chr = $this->read();
247                                                if ($chr != -1 && $chr != $quote)
248                                                        $output .= $chr;
249
250                                                break;
251
252                                        default:
253                                                $output .= $this->read();
254                        }
255
256                        // String terminated
257                        if ($endString)
258                                break;
259                }
260
261                $this->readAway();
262                $this->_value = $output;
263
264                // Needed a property
265                if ($this->_needProp) {
266                        $this->_token = JSON_KEY;
267                        $this->_needProp = false;
268                        return true;
269                }
270
271                if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
272                        $this->_needProp = true;
273
274                return true;
275        }
276
277        function _int2utf8($int) {
278                $int = intval($int);
279
280                switch ($int) {
281                        case 0:
282                                return chr(0);
283
284                        case ($int & 0x7F):
285                                return chr($int);
286
287                        case ($int & 0x7FF):
288                                return chr(0xC0 | (($int >> 6) & 0x1F)) . chr(0x80 | ($int & 0x3F));
289
290                        case ($int & 0xFFFF):
291                                return chr(0xE0 | (($int >> 12) & 0x0F)) . chr(0x80 | (($int >> 6) & 0x3F)) . chr (0x80 | ($int & 0x3F));
292
293                        case ($int & 0x1FFFFF):
294                                return chr(0xF0 | ($int >> 18)) . chr(0x80 | (($int >> 12) & 0x3F)) . chr(0x80 | (($int >> 6) & 0x3F)) . chr(0x80 | ($int & 0x3F));
295                }
296        }
297
298        function _readNumber($start) {
299                $value = "";
300                $isFloat = false;
301
302                $this->_token = JSON_INT;
303                $value .= $start;
304
305                while (($chr = $this->peek()) != -1) {
306                        if (is_numeric($chr) || $chr == '-' || $chr == '.') {
307                                if ($chr == '.')
308                                        $isFloat = true;
309
310                                $value .= $this->read();
311                        } else
312                                break;
313                }
314
315                $this->readAway();
316
317                if ($isFloat) {
318                        $this->_token = JSON_FLOAT;
319                        $this->_value = floatval($value);
320                } else
321                        $this->_value = intval($value);
322
323                if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
324                        $this->_needProp = true;
325
326                return true;
327        }
328
329        function readAway() {
330                while (($chr = $this->peek()) != null) {
331                        if ($chr != ':' && $chr != ',' && $chr != ' ')
332                                return;
333
334                        $this->read();
335                }
336        }
337
338        function read($len = 1) {
339                if ($this->_pos < $this->_len) {
340                        if ($len > 1) {
341                                $str = substr($this->_data, $this->_pos + 1, $len);
342                                $this->_pos += $len;
343
344                                return $str;
345                        } else
346                                return $this->_data[++$this->_pos];
347                }
348
349                return null;
350        }
351
352        function skip($len) {
353                $this->_pos += $len;
354        }
355
356        function peek() {
357                if ($this->_pos < $this->_len)
358                        return $this->_data[$this->_pos + 1];
359
360                return null;
361        }
362}
363
364/**
365 * This class handles JSON stuff.
366 *
367 * @package MCManager.utils
368 */
369class Moxiecode_JSON {
370        public function __construct() {
371        }
372
373    /**
374     * Old syntax of class constructor. Deprecated in PHP7.
375     */
376    public function Moxiecode_JSON() {
377        self::__construct();
378    }
379
380        function decode($input) {
381                $reader = new Moxiecode_JSONReader($input);
382
383                return $this->readValue($reader);
384        }
385
386        function readValue(&$reader) {
387                $this->data = array();
388                $this->parents = array();
389                $this->cur =& $this->data;
390                $key = null;
391                $loc = JSON_IN_ARRAY;
392
393                while ($reader->readToken()) {
394                        switch ($reader->getToken()) {
395                                case JSON_STR:
396                                case JSON_INT:
397                                case JSON_BOOL:
398                                case JSON_FLOAT:
399                                case JSON_NULL:
400                                        switch ($reader->getLocation()) {
401                                                case JSON_IN_OBJECT:
402                                                        $this->cur[$key] = $reader->getValue();
403                                                        break;
404
405                                                case JSON_IN_ARRAY:
406                                                        $this->cur[] = $reader->getValue();
407                                                        break;
408
409                                                default:
410                                                        return $reader->getValue();
411                                        }
412                                        break;
413
414                                case JSON_KEY:
415                                        $key = $reader->getValue();
416                                        break;
417
418                                case JSON_START_OBJ:
419                                case JSON_START_ARRAY:
420                                        if ($loc == JSON_IN_OBJECT)
421                                                $this->addArray($key);
422                                        else
423                                                $this->addArray(null);
424
425                                        $cur =& $obj;
426
427                                        $loc = $reader->getLocation();
428                                        break;
429
430                                case JSON_END_OBJ:
431                                case JSON_END_ARRAY:
432                                        $loc = $reader->getLocation();
433
434                                        if (count($this->parents) > 0) {
435                                                $this->cur =& $this->parents[count($this->parents) - 1];
436                                                array_pop($this->parents);
437                                        }
438                                        break;
439                        }
440                }
441
442                return $this->data[0];
443        }
444
445        // This method was needed since PHP is crapy and doesn't have pointers/references
446        function addArray($key) {
447                $this->parents[] =& $this->cur;
448                $ar = array();
449
450                if ($key)
451                        $this->cur[$key] =& $ar;
452                else
453                        $this->cur[] =& $ar;
454
455                $this->cur =& $ar;
456        }
457
458        function getDelim($index, &$reader) {
459                switch ($reader->getLocation()) {
460                        case JSON_IN_ARRAY:
461                        case JSON_IN_OBJECT:
462                                if ($index > 0)
463                                        return ",";
464                                break;
465                }
466
467                return "";
468        }
469
470        function encode($input) {
471                switch (gettype($input)) {
472                        case 'boolean':
473                                return $input ? 'true' : 'false';
474
475                        case 'integer':
476                                return (int) $input;
477
478                        case 'float':
479                        case 'double':
480                                return (float) $input;
481
482                        case 'NULL':
483                                return 'null';
484
485                        case 'string':
486                                return $this->encodeString($input);
487
488                        case 'array':
489                                return $this->_encodeArray($input);
490
491                        case 'object':
492                                return $this->_encodeArray(get_object_vars($input));
493                }
494
495                return '';
496        }
497
498        function encodeString($input) {
499                // Needs to be escaped
500                if (preg_match('/[^a-zA-Z0-9]/', $input)) {
501                        $output = '';
502
503                        for ($i=0; $i<strlen($input); $i++) {
504                                switch ($input[$i]) {
505                                        case "\b":
506                                                $output .= "\\b";
507                                                break;
508
509                                        case "\t":
510                                                $output .= "\\t";
511                                                break;
512
513                                        case "\f":
514                                                $output .= "\\f";
515                                                break;
516
517                                        case "\r":
518                                                $output .= "\\r";
519                                                break;
520
521                                        case "\n":
522                                                $output .= "\\n";
523                                                break;
524
525                                        case '\\':
526                                                $output .= "\\\\";
527                                                break;
528
529                                        case '\'':
530                                                $output .= "\\'";
531                                                break;
532
533                                        case '"':
534                                                $output .= '\"';
535                                                break;
536
537                                        default:
538                                                $byte = ord($input[$i]);
539
540                                                if (($byte & 0xE0) == 0xC0) {
541                                                        $char = pack('C*', $byte, ord($input[$i + 1]));
542                                                        $i += 1;
543                                                        $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
544                                                } if (($byte & 0xF0) == 0xE0) {
545                                                        $char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]));
546                                                        $i += 2;
547                                                        $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
548                                                } if (($byte & 0xF8) == 0xF0) {
549                                                        $char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]), ord($input[$i + 3]));
550                                                        $i += 3;
551                                                        $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
552                                                } if (($byte & 0xFC) == 0xF8) {
553                                                        $char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]), ord($input[$i + 3]), ord($input[$i + 4]));
554                                                        $i += 4;
555                                                        $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
556                                                } if (($byte & 0xFE) == 0xFC) {
557                                                        $char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]), ord($input[$i + 3]), ord($input[$i + 4]), ord($input[$i + 5]));
558                                                        $i += 5;
559                                                        $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
560                                                } else if ($byte < 128)
561                                                        $output .= $input[$i];
562                                }
563                        }
564
565                        return '"' . $output . '"';
566                }
567
568                return '"' . $input . '"';
569        }
570
571        function _utf82utf16($utf8) {
572                if (function_exists('mb_convert_encoding'))
573                        return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
574
575                switch (strlen($utf8)) {
576                        case 1:
577                                return $utf8;
578
579                        case 2:
580                                return chr(0x07 & (ord($utf8[0]) >> 2)) . chr((0xC0 & (ord($utf8[0]) << 6)) | (0x3F & ord($utf8[1])));
581
582                        case 3:
583                                return chr((0xF0 & (ord($utf8[0]) << 4)) | (0x0F & (ord($utf8[1]) >> 2))) . chr((0xC0 & (ord($utf8[1]) << 6)) | (0x7F & ord($utf8[2])));
584                }
585
586                return '';
587        }
588
589        function _encodeArray($input) {
590                $output = '';
591                $isIndexed = true;
592
593                $keys = array_keys($input);
594                for ($i=0; $i<count($keys); $i++) {
595                        if (!is_int($keys[$i])) {
596                                $output .= $this->encodeString($keys[$i]) . ':' . $this->encode($input[$keys[$i]]);
597                                $isIndexed = false;
598                        } else
599                                $output .= $this->encode($input[$keys[$i]]);
600
601                        if ($i != count($keys) - 1)
602                                $output .= ',';
603                }
604
605                return $isIndexed ? '[' . $output . ']' : '{' . $output . '}';
606        }
607}
608
609?>
Note: See TracBrowser for help on using the repository browser.