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