~chroot64bit/zivios/gentoo-experimental

« back to all changes in this revision

Viewing changes to application/library/Zend/Json/Decoder.php

  • Committer: Mustafa A. Hashmi
  • Date: 2008-12-04 13:32:21 UTC
  • Revision ID: mhashmi@zivios.org-20081204133221-0nd1trunwevijj38
Inclusion of new installation framework with ties to zend layout and dojo layout

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * Zend Framework
 
4
 *
 
5
 * LICENSE
 
6
 *
 
7
 * This source file is subject to the new BSD license that is bundled
 
8
 * with this package in the file LICENSE.txt.
 
9
 * It is also available through the world-wide-web at this URL:
 
10
 * http://framework.zend.com/license/new-bsd
 
11
 * If you did not receive a copy of the license and are unable to
 
12
 * obtain it through the world-wide-web, please send an email
 
13
 * to license@zend.com so we can send you a copy immediately.
 
14
 *
 
15
 * @category   Zend
 
16
 * @package    Zend_Json
 
17
 * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
 
18
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 
19
 */
 
20
 
 
21
/**
 
22
 * @see Zend_Json
 
23
 */
 
24
require_once 'Zend/Json.php';
 
25
 
 
26
/**
 
27
 * @see Zend_Json_Exception
 
28
 */
 
29
require_once 'Zend/Json/Exception.php';
 
30
 
 
31
 
 
32
/**
 
33
 * Decode JSON encoded string to PHP variable constructs
 
34
 *
 
35
 * @category   Zend
 
36
 * @package    Zend_Json
 
37
 * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
 
38
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 
39
 */
 
40
class Zend_Json_Decoder
 
41
{
 
42
    /**
 
43
     * Parse tokens used to decode the JSON object. These are not
 
44
     * for public consumption, they are just used internally to the
 
45
     * class.
 
46
     */
 
47
    const EOF         = 0;
 
48
    const DATUM        = 1;
 
49
    const LBRACE    = 2;
 
50
    const LBRACKET    = 3;
 
51
    const RBRACE     = 4;
 
52
    const RBRACKET    = 5;
 
53
    const COMMA       = 6;
 
54
    const COLON        = 7;
 
55
 
 
56
    /**
 
57
     * Use to maintain a "pointer" to the source being decoded
 
58
     *
 
59
     * @var string
 
60
     */
 
61
    protected $_source;
 
62
 
 
63
    /**
 
64
     * Caches the source length
 
65
     *
 
66
     * @var int
 
67
     */
 
68
    protected $_sourceLength;
 
69
 
 
70
    /**
 
71
     * The offset within the souce being decoded
 
72
     *
 
73
     * @var int
 
74
     *
 
75
     */
 
76
    protected $_offset;
 
77
 
 
78
    /**
 
79
     * The current token being considered in the parser cycle
 
80
     *
 
81
     * @var int
 
82
     */
 
83
    protected $_token;
 
84
 
 
85
    /**
 
86
     * Flag indicating how objects should be decoded
 
87
     *
 
88
     * @var int
 
89
     * @access protected
 
90
     */
 
91
    protected $_decodeType;
 
92
 
 
93
    /**
 
94
     * Constructor
 
95
     *
 
96
     * @param string $source String source to decode
 
97
     * @param int $decodeType How objects should be decoded -- see
 
98
     * {@link Zend_Json::TYPE_ARRAY} and {@link Zend_Json::TYPE_OBJECT} for
 
99
     * valid values
 
100
     * @return void
 
101
     */
 
102
    protected function __construct($source, $decodeType)
 
103
    {
 
104
        // Set defaults
 
105
        $this->_source       = $source;
 
106
        $this->_sourceLength = strlen($source);
 
107
        $this->_token        = self::EOF;
 
108
        $this->_offset       = 0;
 
109
 
 
110
        // Normalize and set $decodeType
 
111
        if (!in_array($decodeType, array(Zend_Json::TYPE_ARRAY, Zend_Json::TYPE_OBJECT)))
 
112
        {
 
113
            $decodeType = Zend_Json::TYPE_ARRAY;
 
114
        }
 
115
        $this->_decodeType   = $decodeType;
 
116
 
 
117
        // Set pointer at first token
 
118
        $this->_getNextToken();
 
119
    }
 
120
 
 
121
    /**
 
122
     * Decode a JSON source string
 
123
     *
 
124
     * Decodes a JSON encoded string. The value returned will be one of the
 
125
     * following:
 
126
     *        - integer
 
127
     *        - float
 
128
     *        - boolean
 
129
     *        - null
 
130
     *      - StdClass
 
131
     *      - array
 
132
     *         - array of one or more of the above types
 
133
     *
 
134
     * By default, decoded objects will be returned as associative arrays; to
 
135
     * return a StdClass object instead, pass {@link Zend_Json::TYPE_OBJECT} to
 
136
     * the $objectDecodeType parameter.
 
137
     *
 
138
     * Throws a Zend_Json_Exception if the source string is null.
 
139
     *
 
140
     * @static
 
141
     * @access public
 
142
     * @param string $source String to be decoded
 
143
     * @param int $objectDecodeType How objects should be decoded; should be
 
144
     * either or {@link Zend_Json::TYPE_ARRAY} or
 
145
     * {@link Zend_Json::TYPE_OBJECT}; defaults to TYPE_ARRAY
 
146
     * @return mixed
 
147
     * @throws Zend_Json_Exception
 
148
     */
 
149
    public static function decode($source = null, $objectDecodeType = Zend_Json::TYPE_ARRAY)
 
150
    {
 
151
        if (null === $source) {
 
152
            throw new Zend_Json_Exception('Must specify JSON encoded source for decoding');
 
153
        } elseif (!is_string($source)) {
 
154
            throw new Zend_Json_Exception('Can only decode JSON encoded strings');
 
155
        }
 
156
 
 
157
        $decoder = new self($source, $objectDecodeType);
 
158
 
 
159
        return $decoder->_decodeValue();
 
160
    }
 
161
 
 
162
 
 
163
    /**
 
164
     * Recursive driving rountine for supported toplevel tops
 
165
     *
 
166
     * @return mixed
 
167
     */
 
168
    protected function _decodeValue()
 
169
    {
 
170
        switch ($this->_token) {
 
171
            case self::DATUM:
 
172
                $result  = $this->_tokenValue;
 
173
                $this->_getNextToken();
 
174
                return($result);
 
175
                break;
 
176
            case self::LBRACE:
 
177
                return($this->_decodeObject());
 
178
                break;
 
179
            case self::LBRACKET:
 
180
                return($this->_decodeArray());
 
181
                break;
 
182
            default:
 
183
                return null;
 
184
                break;
 
185
        }
 
186
    }
 
187
 
 
188
    /**
 
189
     * Decodes an object of the form:
 
190
     *  { "attribute: value, "attribute2" : value,...}
 
191
     *
 
192
     * If Zend_Json_Encoder was used to encode the original object then 
 
193
     * a special attribute called __className which specifies a class
 
194
     * name that should wrap the data contained within the encoded source.
 
195
     *
 
196
     * Decodes to either an array or StdClass object, based on the value of
 
197
     * {@link $_decodeType}. If invalid $_decodeType present, returns as an
 
198
     * array.
 
199
     *
 
200
     * @return array|StdClass
 
201
     */
 
202
    protected function _decodeObject()
 
203
    {
 
204
        $members = array();
 
205
        $tok = $this->_getNextToken();
 
206
 
 
207
        while ($tok && $tok != self::RBRACE) {
 
208
            if ($tok != self::DATUM || ! is_string($this->_tokenValue)) {
 
209
                throw new Zend_Json_Exception('Missing key in object encoding: ' . $this->_source);
 
210
            }
 
211
 
 
212
            $key = $this->_tokenValue;
 
213
            $tok = $this->_getNextToken();
 
214
 
 
215
            if ($tok != self::COLON) {
 
216
                throw new Zend_Json_Exception('Missing ":" in object encoding: ' . $this->_source);
 
217
            }
 
218
 
 
219
            $tok = $this->_getNextToken();
 
220
            $members[$key] = $this->_decodeValue();
 
221
            $tok = $this->_token;
 
222
 
 
223
            if ($tok == self::RBRACE) {
 
224
                break;
 
225
            }
 
226
 
 
227
            if ($tok != self::COMMA) {
 
228
                throw new Zend_Json_Exception('Missing "," in object encoding: ' . $this->_source);
 
229
            }
 
230
 
 
231
            $tok = $this->_getNextToken();
 
232
        }
 
233
 
 
234
        switch ($this->_decodeType) {
 
235
            case Zend_Json::TYPE_OBJECT:
 
236
                // Create new StdClass and populate with $members
 
237
                $result = new StdClass();
 
238
                foreach ($members as $key => $value) {
 
239
                    $result->$key = $value;
 
240
                }
 
241
                break;
 
242
            case Zend_Json::TYPE_ARRAY:
 
243
            default:
 
244
                $result = $members;
 
245
                break;
 
246
        }
 
247
 
 
248
        $this->_getNextToken();
 
249
        return $result;
 
250
    }
 
251
 
 
252
    /**
 
253
     * Decodes a JSON array format:
 
254
     *    [element, element2,...,elementN]
 
255
     *
 
256
     * @return array
 
257
     */
 
258
    protected function _decodeArray()
 
259
    {
 
260
        $result = array();
 
261
        $starttok = $tok = $this->_getNextToken(); // Move past the '['
 
262
        $index  = 0;
 
263
 
 
264
        while ($tok && $tok != self::RBRACKET) {
 
265
            $result[$index++] = $this->_decodeValue();
 
266
 
 
267
            $tok = $this->_token;
 
268
 
 
269
            if ($tok == self::RBRACKET || !$tok) {
 
270
                break;
 
271
            }
 
272
 
 
273
            if ($tok != self::COMMA) {
 
274
                throw new Zend_Json_Exception('Missing "," in array encoding: ' . $this->_source);
 
275
            }
 
276
 
 
277
            $tok = $this->_getNextToken();
 
278
        }
 
279
 
 
280
        $this->_getNextToken();
 
281
        return($result);
 
282
    }
 
283
 
 
284
 
 
285
    /**
 
286
     * Removes whitepsace characters from the source input
 
287
     */
 
288
    protected function _eatWhitespace()
 
289
    {
 
290
        if (preg_match(
 
291
                '/([\t\b\f\n\r ])*/s',
 
292
                $this->_source,
 
293
                $matches,
 
294
                PREG_OFFSET_CAPTURE,
 
295
                $this->_offset)
 
296
            && $matches[0][1] == $this->_offset)
 
297
        {
 
298
            $this->_offset += strlen($matches[0][0]);
 
299
        }
 
300
    }
 
301
 
 
302
 
 
303
    /**
 
304
     * Retrieves the next token from the source stream
 
305
     *
 
306
     * @return int Token constant value specified in class definition
 
307
     */
 
308
    protected function _getNextToken()
 
309
    {
 
310
        $this->_token      = self::EOF;
 
311
        $this->_tokenValue = null;
 
312
        $this->_eatWhitespace();
 
313
 
 
314
        if ($this->_offset >= $this->_sourceLength) {
 
315
            return(self::EOF);
 
316
        }
 
317
 
 
318
        $str        = $this->_source;
 
319
        $str_length = $this->_sourceLength;
 
320
        $i          = $this->_offset;
 
321
        $start      = $i;
 
322
 
 
323
        switch ($str{$i}) {
 
324
            case '{':
 
325
               $this->_token = self::LBRACE;
 
326
               break;
 
327
            case '}':
 
328
                $this->_token = self::RBRACE;
 
329
                break;
 
330
            case '[':
 
331
                $this->_token = self::LBRACKET;
 
332
                break;
 
333
            case ']':
 
334
                $this->_token = self::RBRACKET;
 
335
                break;
 
336
            case ',':
 
337
                $this->_token = self::COMMA;
 
338
                break;
 
339
            case ':':
 
340
                $this->_token = self::COLON;
 
341
                break;
 
342
            case  '"':
 
343
                $result = '';
 
344
                do {
 
345
                    $i++;
 
346
                    if ($i >= $str_length) {
 
347
                        break;
 
348
                    }
 
349
 
 
350
                    $chr = $str{$i};
 
351
                    if ($chr == '\\') {
 
352
                        $i++;
 
353
                        if ($i >= $str_length) {
 
354
                            break;
 
355
                        }
 
356
                        $chr = $str{$i};
 
357
                        switch ($chr) {
 
358
                            case '"' :
 
359
                                $result .= '"';
 
360
                                break;
 
361
                            case '\\':
 
362
                                $result .= '\\';
 
363
                                break;
 
364
                            case '/' :
 
365
                                $result .= '/';
 
366
                                break;
 
367
                            case 'b' :
 
368
                                $result .= chr(8);
 
369
                                break;
 
370
                            case 'f' :
 
371
                                $result .= chr(12);
 
372
                                break;
 
373
                            case 'n' :
 
374
                                $result .= chr(10);
 
375
                                break;
 
376
                            case 'r' :
 
377
                                $result .= chr(13);
 
378
                                break;
 
379
                            case 't' :
 
380
                                $result .= chr(9);
 
381
                                break;
 
382
                            case '\'' :
 
383
                                $result .= '\'';
 
384
                                break;
 
385
                            default:
 
386
                                throw new Zend_Json_Exception("Illegal escape "
 
387
                                    .  "sequence '" . $chr . "'");
 
388
                            }
 
389
                    } elseif ($chr == '"') {
 
390
                        break;
 
391
                    } else {
 
392
                        $result .= $chr;
 
393
                    }
 
394
                } while ($i < $str_length);
 
395
 
 
396
                $this->_token = self::DATUM;
 
397
                //$this->_tokenValue = substr($str, $start + 1, $i - $start - 1);
 
398
                $this->_tokenValue = $result;
 
399
                break;
 
400
            case 't':
 
401
                if (($i+ 3) < $str_length && substr($str, $start, 4) == "true") {
 
402
                    $this->_token = self::DATUM;
 
403
                }
 
404
                $this->_tokenValue = true;
 
405
                $i += 3;
 
406
                break;
 
407
            case 'f':
 
408
                if (($i+ 4) < $str_length && substr($str, $start, 5) == "false") {
 
409
                    $this->_token = self::DATUM;
 
410
                }
 
411
                $this->_tokenValue = false;
 
412
                $i += 4;
 
413
                break;
 
414
            case 'n':
 
415
                if (($i+ 3) < $str_length && substr($str, $start, 4) == "null") {
 
416
                    $this->_token = self::DATUM;
 
417
                }
 
418
                $this->_tokenValue = NULL;
 
419
                $i += 3;
 
420
                break;
 
421
        }
 
422
 
 
423
        if ($this->_token != self::EOF) {
 
424
            $this->_offset = $i + 1; // Consume the last token character
 
425
            return($this->_token);
 
426
        }
 
427
 
 
428
        $chr = $str{$i};
 
429
        if ($chr == '-' || $chr == '.' || ($chr >= '0' && $chr <= '9')) {
 
430
            if (preg_match('/-?([0-9])*(\.[0-9]*)?((e|E)((-|\+)?)[0-9]+)?/s',
 
431
                $str, $matches, PREG_OFFSET_CAPTURE, $start) && $matches[0][1] == $start) {
 
432
 
 
433
                $datum = $matches[0][0];
 
434
 
 
435
                if (is_numeric($datum)) {
 
436
                    if (preg_match('/^0\d+$/', $datum)) {
 
437
                        throw new Zend_Json_Exception("Octal notation not supported by JSON (value: $datum)");
 
438
                    } else {
 
439
                        $val  = intval($datum);
 
440
                        $fVal = floatval($datum);
 
441
                        $this->_tokenValue = ($val == $fVal ? $val : $fVal);
 
442
                    }
 
443
                } else {
 
444
                    throw new Zend_Json_Exception("Illegal number format: $datum");
 
445
                }
 
446
 
 
447
                $this->_token = self::DATUM;
 
448
                $this->_offset = $start + strlen($datum);
 
449
            }
 
450
        } else {
 
451
            throw new Zend_Json_Exception('Illegal Token');
 
452
        }
 
453
 
 
454
        return($this->_token);
 
455
    }
 
456
}
 
457