• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • Examples
  • File List

E:/E/GEAMP/www/openbiz/openbiz/others/Zend/Json/Decoder.php

00001 <?php
00025 require_once 'Zend/Json.php';
00026 
00035 class Zend_Json_Decoder
00036 {
00042     const EOF         = 0;
00043     const DATUM        = 1;
00044     const LBRACE    = 2;
00045     const LBRACKET    = 3;
00046     const RBRACE     = 4;
00047     const RBRACKET    = 5;
00048     const COMMA       = 6;
00049     const COLON        = 7;
00050 
00056     protected $_source;
00057 
00063     protected $_sourceLength;
00064 
00071     protected $_offset;
00072 
00078     protected $_token;
00079 
00086     protected $_decodeType;
00087 
00097     protected function __construct($source, $decodeType)
00098     {
00099         // Set defaults
00100         $this->_source       = self::decodeUnicodeString($source);
00101         $this->_sourceLength = strlen($this->_source);
00102         $this->_token        = self::EOF;
00103         $this->_offset       = 0;
00104 
00105         // Normalize and set $decodeType
00106         if (!in_array($decodeType, array(Zend_Json::TYPE_ARRAY, Zend_Json::TYPE_OBJECT)))
00107         {
00108             $decodeType = Zend_Json::TYPE_ARRAY;
00109         }
00110         $this->_decodeType   = $decodeType;
00111 
00112         // Set pointer at first token
00113         $this->_getNextToken();
00114     }
00115 
00144     public static function decode($source = null, $objectDecodeType = Zend_Json::TYPE_ARRAY)
00145     {
00146         if (null === $source) {
00147             require_once 'Zend/Json/Exception.php';
00148             throw new Zend_Json_Exception('Must specify JSON encoded source for decoding');
00149         } elseif (!is_string($source)) {
00150             require_once 'Zend/Json/Exception.php';
00151             throw new Zend_Json_Exception('Can only decode JSON encoded strings');
00152         }
00153 
00154         $decoder = new self($source, $objectDecodeType);
00155 
00156         return $decoder->_decodeValue();
00157     }
00158 
00159 
00165     protected function _decodeValue()
00166     {
00167         switch ($this->_token) {
00168             case self::DATUM:
00169                 $result  = $this->_tokenValue;
00170                 $this->_getNextToken();
00171                 return($result);
00172                 break;
00173             case self::LBRACE:
00174                 return($this->_decodeObject());
00175                 break;
00176             case self::LBRACKET:
00177                 return($this->_decodeArray());
00178                 break;
00179             default:
00180                 return null;
00181                 break;
00182         }
00183     }
00184 
00199     protected function _decodeObject()
00200     {
00201         $members = array();
00202         $tok = $this->_getNextToken();
00203 
00204         while ($tok && $tok != self::RBRACE) {
00205             if ($tok != self::DATUM || ! is_string($this->_tokenValue)) {
00206                 require_once 'Zend/Json/Exception.php';
00207                 throw new Zend_Json_Exception('Missing key in object encoding: ' . $this->_source);
00208             }
00209 
00210             $key = $this->_tokenValue;
00211             $tok = $this->_getNextToken();
00212 
00213             if ($tok != self::COLON) {
00214                 require_once 'Zend/Json/Exception.php';
00215                 throw new Zend_Json_Exception('Missing ":" in object encoding: ' . $this->_source);
00216             }
00217 
00218             $tok = $this->_getNextToken();
00219             $members[$key] = $this->_decodeValue();
00220             $tok = $this->_token;
00221 
00222             if ($tok == self::RBRACE) {
00223                 break;
00224             }
00225 
00226             if ($tok != self::COMMA) {
00227                 require_once 'Zend/Json/Exception.php';
00228                 throw new Zend_Json_Exception('Missing "," in object encoding: ' . $this->_source);
00229             }
00230 
00231             $tok = $this->_getNextToken();
00232         }
00233 
00234         switch ($this->_decodeType) {
00235             case Zend_Json::TYPE_OBJECT:
00236                 // Create new StdClass and populate with $members
00237                 $result = new StdClass();
00238                 foreach ($members as $key => $value) {
00239                     $result->$key = $value;
00240                 }
00241                 break;
00242             case Zend_Json::TYPE_ARRAY:
00243             default:
00244                 $result = $members;
00245                 break;
00246         }
00247 
00248         $this->_getNextToken();
00249         return $result;
00250     }
00251 
00258     protected function _decodeArray()
00259     {
00260         $result = array();
00261         $starttok = $tok = $this->_getNextToken(); // Move past the '['
00262         $index  = 0;
00263 
00264         while ($tok && $tok != self::RBRACKET) {
00265             $result[$index++] = $this->_decodeValue();
00266 
00267             $tok = $this->_token;
00268 
00269             if ($tok == self::RBRACKET || !$tok) {
00270                 break;
00271             }
00272 
00273             if ($tok != self::COMMA) {
00274                 require_once 'Zend/Json/Exception.php';
00275                 throw new Zend_Json_Exception('Missing "," in array encoding: ' . $this->_source);
00276             }
00277 
00278             $tok = $this->_getNextToken();
00279         }
00280 
00281         $this->_getNextToken();
00282         return($result);
00283     }
00284 
00285 
00289     protected function _eatWhitespace()
00290     {
00291         if (preg_match(
00292                 '/([\t\b\f\n\r ])*/s',
00293                 $this->_source,
00294                 $matches,
00295                 PREG_OFFSET_CAPTURE,
00296                 $this->_offset)
00297             && $matches[0][1] == $this->_offset)
00298         {
00299             $this->_offset += strlen($matches[0][0]);
00300         }
00301     }
00302 
00303 
00309     protected function _getNextToken()
00310     {
00311         $this->_token      = self::EOF;
00312         $this->_tokenValue = null;
00313         $this->_eatWhitespace();
00314 
00315         if ($this->_offset >= $this->_sourceLength) {
00316             return(self::EOF);
00317         }
00318 
00319         $str        = $this->_source;
00320         $str_length = $this->_sourceLength;
00321         $i          = $this->_offset;
00322         $start      = $i;
00323 
00324         switch ($str{$i}) {
00325             case '{':
00326                $this->_token = self::LBRACE;
00327                break;
00328             case '}':
00329                 $this->_token = self::RBRACE;
00330                 break;
00331             case '[':
00332                 $this->_token = self::LBRACKET;
00333                 break;
00334             case ']':
00335                 $this->_token = self::RBRACKET;
00336                 break;
00337             case ',':
00338                 $this->_token = self::COMMA;
00339                 break;
00340             case ':':
00341                 $this->_token = self::COLON;
00342                 break;
00343             case  '"':
00344                 $result = '';
00345                 do {
00346                     $i++;
00347                     if ($i >= $str_length) {
00348                         break;
00349                     }
00350 
00351                     $chr = $str{$i};
00352 
00353                     if ($chr == '\\') {
00354                         $i++;
00355                         if ($i >= $str_length) {
00356                             break;
00357                         }
00358                         $chr = $str{$i};
00359                         switch ($chr) {
00360                             case '"' :
00361                                 $result .= '"';
00362                                 break;
00363                             case '\\':
00364                                 $result .= '\\';
00365                                 break;
00366                             case '/' :
00367                                 $result .= '/';
00368                                 break;
00369                             case 'b' :
00370                                 $result .= chr(8);
00371                                 break;
00372                             case 'f' :
00373                                 $result .= chr(12);
00374                                 break;
00375                             case 'n' :
00376                                 $result .= chr(10);
00377                                 break;
00378                             case 'r' :
00379                                 $result .= chr(13);
00380                                 break;
00381                             case 't' :
00382                                 $result .= chr(9);
00383                                 break;
00384                             case '\'' :
00385                                 $result .= '\'';
00386                                 break;
00387                             default:
00388                                 require_once 'Zend/Json/Exception.php';
00389                                 throw new Zend_Json_Exception("Illegal escape "
00390                                     .  "sequence '" . $chr . "'");
00391                         }
00392                     } elseif($chr == '"') {
00393                         break;
00394                     } else {
00395                         $result .= $chr;
00396                     }
00397                 } while ($i < $str_length);
00398 
00399                 $this->_token = self::DATUM;
00400                 //$this->_tokenValue = substr($str, $start + 1, $i - $start - 1);
00401                 $this->_tokenValue = $result;
00402                 break;
00403             case 't':
00404                 if (($i+ 3) < $str_length && substr($str, $start, 4) == "true") {
00405                     $this->_token = self::DATUM;
00406                 }
00407                 $this->_tokenValue = true;
00408                 $i += 3;
00409                 break;
00410             case 'f':
00411                 if (($i+ 4) < $str_length && substr($str, $start, 5) == "false") {
00412                     $this->_token = self::DATUM;
00413                 }
00414                 $this->_tokenValue = false;
00415                 $i += 4;
00416                 break;
00417             case 'n':
00418                 if (($i+ 3) < $str_length && substr($str, $start, 4) == "null") {
00419                     $this->_token = self::DATUM;
00420                 }
00421                 $this->_tokenValue = NULL;
00422                 $i += 3;
00423                 break;
00424         }
00425 
00426         if ($this->_token != self::EOF) {
00427             $this->_offset = $i + 1; // Consume the last token character
00428             return($this->_token);
00429         }
00430 
00431         $chr = $str{$i};
00432         if ($chr == '-' || $chr == '.' || ($chr >= '0' && $chr <= '9')) {
00433             if (preg_match('/-?([0-9])*(\.[0-9]*)?((e|E)((-|\+)?)[0-9]+)?/s',
00434                 $str, $matches, PREG_OFFSET_CAPTURE, $start) && $matches[0][1] == $start) {
00435 
00436                 $datum = $matches[0][0];
00437 
00438                 if (is_numeric($datum)) {
00439                     if (preg_match('/^0\d+$/', $datum)) {
00440                         require_once 'Zend/Json/Exception.php';
00441                         throw new Zend_Json_Exception("Octal notation not supported by JSON (value: $datum)");
00442                     } else {
00443                         $val  = intval($datum);
00444                         $fVal = floatval($datum);
00445                         $this->_tokenValue = ($val == $fVal ? $val : $fVal);
00446                     }
00447                 } else {
00448                     require_once 'Zend/Json/Exception.php';
00449                     throw new Zend_Json_Exception("Illegal number format: $datum");
00450                 }
00451 
00452                 $this->_token = self::DATUM;
00453                 $this->_offset = $start + strlen($datum);
00454             }
00455         } else {
00456             require_once 'Zend/Json/Exception.php';
00457             throw new Zend_Json_Exception('Illegal Token');
00458         }
00459 
00460         return($this->_token);
00461     }
00462 
00474     public static function decodeUnicodeString($chrs)
00475     {
00476         $delim       = substr($chrs, 0, 1);
00477         $utf8        = '';
00478         $strlen_chrs = strlen($chrs);
00479 
00480         for($i = 0; $i < $strlen_chrs; $i++) {
00481 
00482             $substr_chrs_c_2 = substr($chrs, $i, 2);
00483             $ord_chrs_c = ord($chrs[$i]);
00484 
00485             switch (true) {
00486                 case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $i, 6)):
00487                     // single, escaped unicode character
00488                     $utf16 = chr(hexdec(substr($chrs, ($i + 2), 2)))
00489                            . chr(hexdec(substr($chrs, ($i + 4), 2)));
00490                     $utf8 .= self::_utf162utf8($utf16);
00491                     $i += 5;
00492                     break;
00493                 case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
00494                     $utf8 .= $chrs{$i};
00495                     break;
00496                 case ($ord_chrs_c & 0xE0) == 0xC0:
00497                     // characters U-00000080 - U-000007FF, mask 110XXXXX
00498                     //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
00499                     $utf8 .= substr($chrs, $i, 2);
00500                     ++$i;
00501                     break;
00502                 case ($ord_chrs_c & 0xF0) == 0xE0:
00503                     // characters U-00000800 - U-0000FFFF, mask 1110XXXX
00504                     // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
00505                     $utf8 .= substr($chrs, $i, 3);
00506                     $i += 2;
00507                     break;
00508                 case ($ord_chrs_c & 0xF8) == 0xF0:
00509                     // characters U-00010000 - U-001FFFFF, mask 11110XXX
00510                     // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
00511                     $utf8 .= substr($chrs, $i, 4);
00512                     $i += 3;
00513                     break;
00514                 case ($ord_chrs_c & 0xFC) == 0xF8:
00515                     // characters U-00200000 - U-03FFFFFF, mask 111110XX
00516                     // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
00517                     $utf8 .= substr($chrs, $i, 5);
00518                     $i += 4;
00519                     break;
00520                 case ($ord_chrs_c & 0xFE) == 0xFC:
00521                     // characters U-04000000 - U-7FFFFFFF, mask 1111110X
00522                     // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
00523                     $utf8 .= substr($chrs, $i, 6);
00524                     $i += 5;
00525                     break;
00526             }
00527         }
00528 
00529         return $utf8;
00530     }
00531 
00545     protected static function _utf162utf8($utf16)
00546     {
00547         // Check for mb extension otherwise do by hand.
00548         if( function_exists('mb_convert_encoding') ) {
00549             return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
00550         }
00551 
00552         $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
00553 
00554         switch (true) {
00555             case ((0x7F & $bytes) == $bytes):
00556                 // this case should never be reached, because we are in ASCII range
00557                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
00558                 return chr(0x7F & $bytes);
00559 
00560             case (0x07FF & $bytes) == $bytes:
00561                 // return a 2-byte UTF-8 character
00562                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
00563                 return chr(0xC0 | (($bytes >> 6) & 0x1F))
00564                      . chr(0x80 | ($bytes & 0x3F));
00565 
00566             case (0xFFFF & $bytes) == $bytes:
00567                 // return a 3-byte UTF-8 character
00568                 // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
00569                 return chr(0xE0 | (($bytes >> 12) & 0x0F))
00570                      . chr(0x80 | (($bytes >> 6) & 0x3F))
00571                      . chr(0x80 | ($bytes & 0x3F));
00572         }
00573 
00574         // ignoring UTF-32 for now, sorry
00575         return '';
00576     }
00577 }
00578 

Generated on Thu Apr 19 2012 17:01:17 for openbiz by  doxygen 1.7.2