Open-Source PHP Framework - Designed for rapid development of performance-oriented scalable applications

/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 != -&& $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*'$byteord($input[$i 1]));
528                             
$i += 1;
529                             
$output .= sprintf('\u%04s'bin2hex($this->_utf82utf16($char)));
530                         } if ((
$byte 0xF0) == 0xE0) {
531                             
$char pack('C*'$byteord($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*'$byteord($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*'$byteord($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*'$byteord($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