/webroot/js/tinymce/plugins/spellchecker/classes/utils/JSON.php
[return to app]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 ?>
596