developer.jelix.org is not used any more and exists only for history. Post new tickets on the Github account.
developer.jelix.org n'est plus utilisée, et existe uniquement pour son historique. Postez les nouveaux tickets sur le compte github.

Ticket #231: json-utf8-patch.diff

File json-utf8-patch.diff, 60.4 KB (added by Julien, 13 years ago)

Patch JSON-UTF8

  • lib/json/JSON.php

     
    11<?php
    2     // +----------------------------------------------------------------------+
    3     // | PHP version 4                                                        |
    4     // +----------------------------------------------------------------------+
    5     // | Copyright (c) 2005 Michal Migurski                                   |
    6     // +----------------------------------------------------------------------+
    7     // | This source file is subject to version 3.0 of the PHP license,       |
    8     // | that is bundled with this package in the file LICENSE, and is        |
    9     // | available through the world-wide-web at the following url:           |
    10     // | http://www.php.net/license/3_0.txt.                                  |
    11     // | If you did not receive a copy of the PHP license and are unable to   |
    12     // | obtain it through the world-wide-web, please send a note to          |
    13     // | license@php.net so we can mail you a copy immediately.               |
    14     // +----------------------------------------------------------------------+
    15     // | Author: Michal Migurski, mike-json[at]teczno[dot]com                 |
    16     // | with contributions from:                                             |
    17     // |   Matt Knapp, mdknapp[at]gmail[dot]com                               |
    18     // |   Brett Stimmerman, brettstimmerman[at]gmail[dot]com                 |
    19     // +----------------------------------------------------------------------+
    20     //
    21     // $Id: JSON.php,v 1.15 2005/06/03 17:31:47 migurski Exp $
    22     /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
     2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
    233
    24     define('JSON_SLICE',   1);
    25     define('JSON_IN_STR',  2);
    26     define('JSON_IN_ARR',  4);
    27     define('JSON_IN_OBJ',  8);
    28     define('JSON_IN_CMT', 16);
    29     define('JSON_LOOSE_TYPE', 10);
    30     define('JSON_STRICT_TYPE', 11);
    31    
    32    /** JSON
    33     * Conversion to and from JSON format.
    34     * See http://json.org for details.
     4/**
     5* Converts to and from JSON format.
     6*
     7* JSON (JavaScript Object Notation) is a lightweight data-interchange
     8* format. It is easy for humans to read and write. It is easy for machines
     9* to parse and generate. It is based on a subset of the JavaScript
     10* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
     11* This feature can also be found in  Python. JSON is a text format that is
     12* completely language independent but uses conventions that are familiar
     13* to programmers of the C-family of languages, including C, C++, C#, Java,
     14* JavaScript, Perl, TCL, and many others. These properties make JSON an
     15* ideal data-interchange language.
     16*
     17* This package provides a simple encoder and decoder for JSON notation. It
     18* is intended for use with client-side Javascript applications that make
     19* use of HTTPRequest to perform server communication functions - data can
     20* be encoded into JSON notation for use in a client-side javascript, or
     21* decoded from incoming Javascript requests. JSON format is native to
     22* Javascript, and can be directly eval()'ed with no further parsing
     23* overhead
     24*
     25* All strings should be in ASCII or UTF-8 format!
     26*
     27* LICENSE: Redistribution and use in source and binary forms, with or
     28* without modification, are permitted provided that the following
     29* conditions are met: Redistributions of source code must retain the
     30* above copyright notice, this list of conditions and the following
     31* disclaimer. Redistributions in binary form must reproduce the above
     32* copyright notice, this list of conditions and the following disclaimer
     33* in the documentation and/or other materials provided with the
     34* distribution.
     35*
     36* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
     37* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     38* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
     39* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     40* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     41* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     42* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     43* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
     44* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
     45* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
     46* DAMAGE.
     47*
     48* @category
     49* @package     Services_JSON
     50* @author      Michal Migurski <mike-json@teczno.com>
     51* @author      Matt Knapp <mdknapp[at]gmail[dot]com>
     52* @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
     53* @copyright   2005 Michal Migurski
     54* @version     CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
     55* @license     http://www.opensource.org/licenses/bsd-license.php
     56* @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198
     57*/
     58
     59/**
     60* Marker constant for Services_JSON::decode(), used to flag stack state
     61*/
     62define('SERVICES_JSON_SLICE',   1);
     63
     64/**
     65* Marker constant for Services_JSON::decode(), used to flag stack state
     66*/
     67define('SERVICES_JSON_IN_STR',  2);
     68
     69/**
     70* Marker constant for Services_JSON::decode(), used to flag stack state
     71*/
     72define('SERVICES_JSON_IN_ARR',  3);
     73
     74/**
     75* Marker constant for Services_JSON::decode(), used to flag stack state
     76*/
     77define('SERVICES_JSON_IN_OBJ',  4);
     78
     79/**
     80* Marker constant for Services_JSON::decode(), used to flag stack state
     81*/
     82define('SERVICES_JSON_IN_CMT', 5);
     83
     84/**
     85* Behavior switch for Services_JSON::decode()
     86*/
     87define('SERVICES_JSON_LOOSE_TYPE', 16);
     88
     89/**
     90* Behavior switch for Services_JSON::decode()
     91*/
     92define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
     93
     94/**
     95* Converts to and from JSON format.
     96*
     97* Brief example of use:
     98*
     99* <code>
     100* // create a new instance of Services_JSON
     101* $json = new Services_JSON();
     102*
     103* // convert a complexe value to JSON notation, and send it to the browser
     104* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
     105* $output = $json->encode($value);
     106*
     107* print($output);
     108* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
     109*
     110* // accept incoming POST data, assumed to be in JSON notation
     111* $input = file_get_contents('php://input', 1000000);
     112* $value = $json->decode($input);
     113* </code>
     114*/
     115class Services_JSON
     116{
     117   /**
     118    * constructs a new JSON instance
    35119    *
    36     * note all strings should be in ASCII or UTF-8 format!
     120    * @param    int     $use    object behavior flags; combine with boolean-OR
     121    *
     122    *                           possible values:
     123    *                           - SERVICES_JSON_LOOSE_TYPE:  loose typing.
     124    *                                   "{...}" syntax creates associative arrays
     125    *                                   instead of objects in decode().
     126    *                           - SERVICES_JSON_SUPPRESS_ERRORS:  error suppression.
     127    *                                   Values which can't be encoded (e.g. resources)
     128    *                                   appear as NULL instead of throwing errors.
     129    *                                   By default, a deeply-nested resource will
     130    *                                   bubble up with an error, so all return values
     131    *                                   from encode() should be checked with isError()
    37132    */
    38     class JSON
     133    function Services_JSON($use = 0)
    39134    {
    40        /** function JSON
    41         * constructor
    42         *
    43         * @param    use     int     object behavior: when encoding or decoding,
    44         *                           be loose or strict about object/array usage
    45         *
    46         *                           possible values:
    47         *                              JSON_STRICT_TYPE - strict typing, default
    48         *                                                 "{...}" syntax creates objects in decode
    49         *                               JSON_LOOSE_TYPE - loose typing
    50         *                                                 "{...}" syntax creates associative arrays in decode
    51         */
    52         function JSON($use=JSON_STRICT_TYPE)
    53         {
    54             $this->use = $use;
     135        $this->use = $use;
     136    }
     137
     138   /**
     139    * convert a string from one UTF-16 char to one UTF-8 char
     140    *
     141    * Normally should be handled by mb_convert_encoding, but
     142    * provides a slower PHP-only method for installations
     143    * that lack the multibye string extension.
     144    *
     145    * @param    string  $utf16  UTF-16 character
     146    * @return   string  UTF-8 character
     147    * @access   private
     148    */
     149    function utf162utf8($utf16)
     150    {
     151        // oh please oh please oh please oh please oh please
     152        if(function_exists('mb_convert_encoding')) {
     153            return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
    55154        }
    56155
    57        /** function encode
    58         * encode an arbitrary variable into JSON format
    59         *
    60         * @param    var     mixed   any number, boolean, string, array, or object to be encoded.
    61         *                           see argument 1 to JSON() above for array-parsing behavior.
    62         *                           if var is a strng, note that encode() always expects it
    63         *                           to be in ASCII or UTF-8 format!
    64         *
    65         * @return   string  JSON string representation of input var
    66         */
    67         function encode($var)
    68         {
    69             switch(gettype($var)) {
    70                 case 'boolean':
    71                     return $var ? 'true' : 'false';
    72                
    73                 case 'NULL':
    74                     return 'null';
    75                
    76                 case 'integer':
    77                     return sprintf('%d', $var);
    78                    
    79                 case 'double':
    80                 case 'float':
    81                     return sprintf('%f', $var);
    82                    
    83                 case 'string': // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
    84                     $ascii = '';
    85                     $strlen_var = strlen($var);
    86    
    87                     for($c = 0; $c < $strlen_var; $c++) {
    88                        
    89                         $ord_var_c = ord($var{$c});
    90                
    91                         if($ord_var_c == 0x08) {
     156        $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
     157
     158        switch(true) {
     159            case ((0x7F & $bytes) == $bytes):
     160                // this case should never be reached, because we are in ASCII range
     161                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     162                return chr(0x7F & $bytes);
     163
     164            case (0x07FF & $bytes) == $bytes:
     165                // return a 2-byte UTF-8 character
     166                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     167                return chr(0xC0 | (($bytes >> 6) & 0x1F))
     168                     . chr(0x80 | ($bytes & 0x3F));
     169
     170            case (0xFFFF & $bytes) == $bytes:
     171                // return a 3-byte UTF-8 character
     172                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     173                return chr(0xE0 | (($bytes >> 12) & 0x0F))
     174                     . chr(0x80 | (($bytes >> 6) & 0x3F))
     175                     . chr(0x80 | ($bytes & 0x3F));
     176        }
     177
     178        // ignoring UTF-32 for now, sorry
     179        return '';
     180    }
     181
     182   /**
     183    * convert a string from one UTF-8 char to one UTF-16 char
     184    *
     185    * Normally should be handled by mb_convert_encoding, but
     186    * provides a slower PHP-only method for installations
     187    * that lack the multibye string extension.
     188    *
     189    * @param    string  $utf8   UTF-8 character
     190    * @return   string  UTF-16 character
     191    * @access   private
     192    */
     193    function utf82utf16($utf8)
     194    {
     195        // oh please oh please oh please oh please oh please
     196        if(function_exists('mb_convert_encoding')) {
     197            return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
     198        }
     199
     200        switch(strlen($utf8)) {
     201            case 1:
     202                // this case should never be reached, because we are in ASCII range
     203                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     204                return $utf8;
     205
     206            case 2:
     207                // return a UTF-16 character from a 2-byte UTF-8 char
     208                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     209                return chr(0x07 & (ord($utf8{0}) >> 2))
     210                     . chr((0xC0 & (ord($utf8{0}) << 6))
     211                         | (0x3F & ord($utf8{1})));
     212
     213            case 3:
     214                // return a UTF-16 character from a 3-byte UTF-8 char
     215                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     216                return chr((0xF0 & (ord($utf8{0}) << 4))
     217                         | (0x0F & (ord($utf8{1}) >> 2)))
     218                     . chr((0xC0 & (ord($utf8{1}) << 6))
     219                         | (0x7F & ord($utf8{2})));
     220        }
     221
     222        // ignoring UTF-32 for now, sorry
     223        return '';
     224    }
     225
     226   /**
     227    * encodes an arbitrary variable into JSON format
     228    *
     229    * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
     230    *                           see argument 1 to Services_JSON() above for array-parsing behavior.
     231    *                           if var is a strng, note that encode() always expects it
     232    *                           to be in ASCII or UTF-8 format!
     233    *
     234    * @return   mixed   JSON string representation of input var or an error if a problem occurs
     235    * @access   public
     236    */
     237    function encode($var)
     238    {
     239        switch (gettype($var)) {
     240            case 'boolean':
     241                return $var ? 'true' : 'false';
     242
     243            case 'NULL':
     244                return 'null';
     245
     246            case 'integer':
     247                return (int) $var;
     248
     249            case 'double':
     250            case 'float':
     251                return (float) $var;
     252
     253            case 'string':
     254                // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
     255                $ascii = '';
     256                $strlen_var = strlen($var);
     257
     258               /*
     259                * Iterate over every character in the string,
     260                * escaping with a slash or encoding to UTF-8 where necessary
     261                */
     262                for ($c = 0; $c < $strlen_var; ++$c) {
     263
     264                    $ord_var_c = ord($var{$c});
     265
     266                    switch (true) {
     267                        case $ord_var_c == 0x08:
    92268                            $ascii .= '\b';
    93                        
    94                         } elseif($ord_var_c == 0x09) {
     269                            break;
     270                        case $ord_var_c == 0x09:
    95271                            $ascii .= '\t';
    96                        
    97                         } elseif($ord_var_c == 0x0A) {
     272                            break;
     273                        case $ord_var_c == 0x0A:
    98274                            $ascii .= '\n';
    99                        
    100                         } elseif($ord_var_c == 0x0C) {
     275                            break;
     276                        case $ord_var_c == 0x0C:
    101277                            $ascii .= '\f';
    102                        
    103                         } elseif($ord_var_c == 0x0D) {
     278                            break;
     279                        case $ord_var_c == 0x0D:
    104280                            $ascii .= '\r';
    105                        
    106                         } elseif(($ord_var_c == 0x22) || ($ord_var_c == 0x2F) || ($ord_var_c == 0x5C)) {
    107                             $ascii .= '\\'.$var{$c}; // double quote, slash, slosh
    108                        
    109                         } elseif(($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)) {
     281                            break;
     282
     283                        case $ord_var_c == 0x22:
     284                        case $ord_var_c == 0x2F:
     285                        case $ord_var_c == 0x5C:
     286                            // double quote, slash, slosh
     287                            $ascii .= '\\'.$var{$c};
     288                            break;
     289
     290                        case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
    110291                            // characters U-00000000 - U-0000007F (same as ASCII)
    111                             $ascii .= $var{$c}; // most normal ASCII chars
    112                
    113                         } elseif(($ord_var_c & 0xE0) == 0xC0) {
    114                             // characters U-00000080 - U-000007FF, mask 110XXXXX, see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    115                             $char = pack('C*', $ord_var_c, ord($var{$c+1})); $c+=1;
    116                             $ascii .= sprintf('\u%04s', bin2hex(mb_convert_encoding($char, 'UTF-16', 'UTF-8')));
    117    
    118                         } elseif(($ord_var_c & 0xF0) == 0xE0) {
    119                             // characters U-00000800 - U-0000FFFF, mask 1110XXXX, see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    120                             $char = pack('C*', $ord_var_c, ord($var{$c+1}), ord($var{$c+2})); $c+=2;
    121                             $ascii .= sprintf('\u%04s', bin2hex(mb_convert_encoding($char, 'UTF-16', 'UTF-8')));
    122    
    123                         } elseif(($ord_var_c & 0xF8) == 0xF0) {
    124                             // characters U-00010000 - U-001FFFFF, mask 11110XXX, see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    125                             $char = pack('C*', $ord_var_c, ord($var{$c+1}), ord($var{$c+2}), ord($var{$c+3})); $c+=3;
    126                             $ascii .= sprintf('\u%04s', bin2hex(mb_convert_encoding($char, 'UTF-16', 'UTF-8')));
    127    
    128                         } elseif(($ord_var_c & 0xFC) == 0xF8) {
    129                             // characters U-00200000 - U-03FFFFFF, mask 111110XX, see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    130                             $char = pack('C*', $ord_var_c, ord($var{$c+1}), ord($var{$c+2}), ord($var{$c+3}), ord($var{$c+4})); $c+=4;
    131                             $ascii .= sprintf('\u%04s', bin2hex(mb_convert_encoding($char, 'UTF-16', 'UTF-8')));
    132    
    133                         } elseif(($ord_var_c & 0xFE) == 0xFC) {
    134                             // characters U-04000000 - U-7FFFFFFF, mask 1111110X, see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
    135                             $char = pack('C*', $ord_var_c, ord($var{$c+1}), ord($var{$c+2}), ord($var{$c+3}), ord($var{$c+4}), ord($var{$c+5})); $c+=5;
    136                             $ascii .= sprintf('\u%04s', bin2hex(mb_convert_encoding($char, 'UTF-16', 'UTF-8')));
    137    
     292                            $ascii .= $var{$c};
     293                            break;
     294
     295                        case (($ord_var_c & 0xE0) == 0xC0):
     296                            // characters U-00000080 - U-000007FF, mask 110XXXXX
     297                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     298                            $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
     299                            $c += 1;
     300                            $utf16 = $this->utf82utf16($char);
     301                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
     302                            break;
     303
     304                        case (($ord_var_c & 0xF0) == 0xE0):
     305                            // characters U-00000800 - U-0000FFFF, mask 1110XXXX
     306                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     307                            $char = pack('C*', $ord_var_c,
     308                                         ord($var{$c + 1}),
     309                                         ord($var{$c + 2}));
     310                            $c += 2;
     311                            $utf16 = $this->utf82utf16($char);
     312                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
     313                            break;
     314
     315                        case (($ord_var_c & 0xF8) == 0xF0):
     316                            // characters U-00010000 - U-001FFFFF, mask 11110XXX
     317                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     318                            $char = pack('C*', $ord_var_c,
     319                                         ord($var{$c + 1}),
     320                                         ord($var{$c + 2}),
     321                                         ord($var{$c + 3}));
     322                            $c += 3;
     323                            $utf16 = $this->utf82utf16($char);
     324                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
     325                            break;
     326
     327                        case (($ord_var_c & 0xFC) == 0xF8):
     328                            // characters U-00200000 - U-03FFFFFF, mask 111110XX
     329                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     330                            $char = pack('C*', $ord_var_c,
     331                                         ord($var{$c + 1}),
     332                                         ord($var{$c + 2}),
     333                                         ord($var{$c + 3}),
     334                                         ord($var{$c + 4}));
     335                            $c += 4;
     336                            $utf16 = $this->utf82utf16($char);
     337                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
     338                            break;
     339
     340                        case (($ord_var_c & 0xFE) == 0xFC):
     341                            // characters U-04000000 - U-7FFFFFFF, mask 1111110X
     342                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     343                            $char = pack('C*', $ord_var_c,
     344                                         ord($var{$c + 1}),
     345                                         ord($var{$c + 2}),
     346                                         ord($var{$c + 3}),
     347                                         ord($var{$c + 4}),
     348                                         ord($var{$c + 5}));
     349                            $c += 5;
     350                            $utf16 = $this->utf82utf16($char);
     351                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
     352                            break;
     353                    }
     354                }
     355
     356                return '"'.$ascii.'"';
     357
     358            case 'array':
     359               /*
     360                * As per JSON spec if any array key is not an integer
     361                * we must treat the the whole array as an object. We
     362                * also try to catch a sparsely populated associative
     363                * array with numeric keys here because some JS engines
     364                * will create an array with empty indexes up to
     365                * max_index which can cause memory issues and because
     366                * the keys, which may be relevant, will be remapped
     367                * otherwise.
     368                *
     369                * As per the ECMA and JSON specification an object may
     370                * have any string as a property. Unfortunately due to
     371                * a hole in the ECMA specification if the key is a
     372                * ECMA reserved word or starts with a digit the
     373                * parameter is only accessible using ECMAScript's
     374                * bracket notation.
     375                */
     376
     377                // treat as a JSON object
     378                if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
     379                    $properties = array_map(array($this, 'name_value'),
     380                                            array_keys($var),
     381                                            array_values($var));
     382
     383                    foreach($properties as $property) {
     384                        if(Services_JSON::isError($property)) {
     385                            return $property;
    138386                        }
    139387                    }
    140                    
    141                     return sprintf('"%s"', $ascii);
    142                    
    143                 case 'array':
    144                     // As per JSON spec if any array key is not an integer we must treat the the whole array as an object.
    145                         // We also try to catch a sparsely populated associative array with numeric keys here because some JS
    146                         // engines will create an array with empty indexes up to max_index which can cause memory issues
    147                         // and because the keys, which may be relevant, will be remapped otherwise.
    148                         //
    149                     // As per the ECMA and JSON specification an object may have any string as a property. Unfortunately due to a
    150                     // hole in the ECMA specification if the key is a ECMA reserved word or starts with a digit the parameter is only
    151                     // accessible using ECMAScript's bracket notation. 
    152                    
    153                     // treat as a JSON object 
    154                     if(is_array($var) && (array_keys($var) !== range(0, sizeof($var) - 1)))
    155                         return sprintf('{%s}', join(',', array_map(array($this, 'name_value'), array_keys($var), array_values($var))));
    156388
    157                     // treat it like a regular array
    158                     return sprintf('[%s]', join(',', array_map(array($this, 'encode'), $var)));
    159                    
    160                 case 'object':
    161                     $vars = get_object_vars($var);
    162                     return sprintf('{%s}', join(',', array_map(array($this, 'name_value'), array_keys($vars), array_values($vars))));                   
     389                    return '{' . join(',', $properties) . '}';
     390                }
    163391
    164                 default:
    165                     return '';
    166             }
     392                // treat it like a regular array
     393                $elements = array_map(array($this, 'encode'), $var);
     394
     395                foreach($elements as $element) {
     396                    if(Services_JSON::isError($element)) {
     397                        return $element;
     398                    }
     399                }
     400
     401                return '[' . join(',', $elements) . ']';
     402
     403            case 'object':
     404                $vars = get_object_vars($var);
     405
     406                $properties = array_map(array($this, 'name_value'),
     407                                        array_keys($vars),
     408                                        array_values($vars));
     409
     410                foreach($properties as $property) {
     411                    if(Services_JSON::isError($property)) {
     412                        return $property;
     413                    }
     414                }
     415
     416                return '{' . join(',', $properties) . '}';
     417
     418            default:
     419                return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
     420                    ? 'null'
     421                    : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
    167422        }
    168        
    169        /** function enc
    170         * alias for encode()
    171         */
    172         function enc($var)
    173         {
    174             return $this->encode($var);
    175         }
    176        
    177        /** function name_value
    178         * array-walking function for use in generating JSON-formatted name-value pairs
    179         *
    180         * @param    name    string  name of key to use
    181         * @param    value   mixed   reference to an array element to be encoded
    182         *
    183         * @return   string  JSON-formatted name-value pair, like '"name":value'
    184         */
    185         function name_value($name, $value)
    186         {
    187             return (sprintf("%s:%s", $this->encode(strval($name)), $this->encode($value)));
    188         }       
     423    }
    189424
    190        /** function reduce_string
    191         * reduce a string by removing leading and trailing comments and whitespace
    192         *
    193         * @param    str     string      string value to strip of comments and whitespace
    194         *
    195         * @return   string  string value stripped of comments and whitespace
    196         */
    197         function reduce_string($str)
    198         {
    199             $str = preg_replace('#^\s*//(.+)$#m', '', $str); // eliminate single line comments in '// ...' form
    200             $str = preg_replace('#^\s*/\*(.+)\*/#Us', '', $str); // eliminate multi-line comments in '/* ... */' form, at start of string
    201             $str = preg_replace('#/\*(.+)\*/\s*$#Us', '', $str); // eliminate multi-line comments in '/* ... */' form, at end of string
    202             $str = trim($str); // eliminate extraneous space
    203            
    204             return $str;
     425   /**
     426    * array-walking function for use in generating JSON-formatted name-value pairs
     427    *
     428    * @param    string  $name   name of key to use
     429    * @param    mixed   $value  reference to an array element to be encoded
     430    *
     431    * @return   string  JSON-formatted name-value pair, like '"name":value'
     432    * @access   private
     433    */
     434    function name_value($name, $value)
     435    {
     436        $encoded_value = $this->encode($value);
     437
     438        if(Services_JSON::isError($encoded_value)) {
     439            return $encoded_value;
    205440        }
    206441
    207        /** function decode
    208         * decode a JSON string into appropriate variable
    209         *
    210         * @param    str     string  JSON-formatted string
    211         *
    212         * @return   mixed   number, boolean, string, array, or object
    213         *                   corresponding to given JSON input string.
    214         *                   see argument 1 to JSON() above for object-output behavior.
    215         *                   note that decode() always returns strings
    216         *                   in ASCII or UTF-8 format!
    217         */
    218         function decode($str)
    219         {
    220             $str = $this->reduce_string($str);
    221        
    222             switch(strtolower($str)) {
    223                 case 'true':
    224                     return true;
    225    
    226                 case 'false':
    227                     return false;
    228                
    229                 case 'null':
    230                     return null;
    231                
    232                 default:
    233                     if(is_numeric($str)) { // Lookie-loo, it's a number
    234                         // return (float)$str; // This would work on its own, but I'm trying to be good about returning integers where appropriate
    235                         return ((float)$str == (integer)$str)
    236                             ? (integer)$str
    237                             : (float)$str;
    238                        
    239                     } elseif(preg_match('/^".+"$/s', $str) || preg_match('/^\'.+\'$/s', $str)) { // STRINGS RETURNED IN UTF-8 FORMAT
    240                         $delim = substr($str, 0, 1);
    241                         $chrs = substr($str, 1, -1);
    242                         $utf8 = '';
    243                         $strlen_chrs = strlen($chrs);
    244                        
    245                         for($c = 0; $c < $strlen_chrs; $c++) {
    246                        
    247                             $substr_chrs_c_2 = substr($chrs, $c, 2);
     442        return $this->encode(strval($name)) . ':' . $encoded_value;
     443    }
    248444
    249                             if($substr_chrs_c_2 == '\b') {
    250                                 $utf8 .= chr(0x08); $c+=1;
    251    
    252                             } elseif($substr_chrs_c_2 == '\t') {
    253                                 $utf8 .= chr(0x09); $c+=1;
    254    
    255                             } elseif($substr_chrs_c_2 == '\n') {
    256                                 $utf8 .= chr(0x0A); $c+=1;
    257    
    258                             } elseif($substr_chrs_c_2 == '\f') {
    259                                 $utf8 .= chr(0x0C); $c+=1;
    260    
    261                             } elseif($substr_chrs_c_2 == '\r') {
    262                                 $utf8 .= chr(0x0D); $c+=1;
    263    
    264                             } elseif(($delim == '"') && (($substr_chrs_c_2 == '\\"') || ($substr_chrs_c_2 == '\\\\') || ($substr_chrs_c_2 == '\\/'))) {
    265                                 $utf8 .= $chrs{++$c};
    266    
    267                             } elseif(($delim == "'") && (($substr_chrs_c_2 == '\\\'') || ($substr_chrs_c_2 == '\\\\') || ($substr_chrs_c_2 == '\\/'))) {
    268                                 $utf8 .= $chrs{++$c};
    269    
    270                             } elseif(preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6))) { // single, escaped unicode character
    271                                 $utf16 = chr(hexdec(substr($chrs, ($c+2), 2))) . chr(hexdec(substr($chrs, ($c+4), 2)));
    272                                 $utf8 .= mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
    273                                 $c+=5;
    274    
    275                             } elseif((ord($chrs{$c}) >= 0x20) && (ord($chrs{$c}) <= 0x7F)) {
     445   /**
     446    * reduce a string by removing leading and trailing comments and whitespace
     447    *
     448    * @param    $str    string      string value to strip of comments and whitespace
     449    *
     450    * @return   string  string value stripped of comments and whitespace
     451    * @access   private
     452    */
     453    function reduce_string($str)
     454    {
     455        $str = preg_replace(array(
     456
     457                // eliminate single line comments in '// ...' form
     458                '#^\s*//(.+)$#m',
     459
     460                // eliminate multi-line comments in '/* ... */' form, at start of string
     461                '#^\s*/\*(.+)\*/#Us',
     462
     463                // eliminate multi-line comments in '/* ... */' form, at end of string
     464                '#/\*(.+)\*/\s*$#Us'
     465
     466            ), '', $str);
     467
     468        // eliminate extraneous space
     469        return trim($str);
     470    }
     471
     472   /**
     473    * decodes a JSON string into appropriate variable
     474    *
     475    * @param    string  $str    JSON-formatted string
     476    *
     477    * @return   mixed   number, boolean, string, array, or object
     478    *                   corresponding to given JSON input string.
     479    *                   See argument 1 to Services_JSON() above for object-output behavior.
     480    *                   Note that decode() always returns strings
     481    *                   in ASCII or UTF-8 format!
     482    * @access   public
     483    */
     484    function decode($str)
     485    {
     486        $str = $this->reduce_string($str);
     487
     488        switch (strtolower($str)) {
     489            case 'true':
     490                return true;
     491
     492            case 'false':
     493                return false;
     494
     495            case 'null':
     496                return null;
     497
     498            default:
     499                $m = array();
     500
     501                if (is_numeric($str)) {
     502                    // Lookie-loo, it's a number
     503
     504                    // This would work on its own, but I'm trying to be
     505                    // good about returning integers where appropriate:
     506                    // return (float)$str;
     507
     508                    // Return float or int, as appropriate
     509                    return ((float)$str == (integer)$str)
     510                        ? (integer)$str
     511                        : (float)$str;
     512
     513                } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
     514                    // STRINGS RETURNED IN UTF-8 FORMAT
     515                    $delim = substr($str, 0, 1);
     516                    $chrs = substr($str, 1, -1);
     517                    $utf8 = '';
     518                    $strlen_chrs = strlen($chrs);
     519
     520                    for ($c = 0; $c < $strlen_chrs; ++$c) {
     521
     522                        $substr_chrs_c_2 = substr($chrs, $c, 2);
     523                        $ord_chrs_c = ord($chrs{$c});
     524
     525                        switch (true) {
     526                            case $substr_chrs_c_2 == '\b':
     527                                $utf8 .= chr(0x08);
     528                                ++$c;
     529                                break;
     530                            case $substr_chrs_c_2 == '\t':
     531                                $utf8 .= chr(0x09);
     532                                ++$c;
     533                                break;
     534                            case $substr_chrs_c_2 == '\n':
     535                                $utf8 .= chr(0x0A);
     536                                ++$c;
     537                                break;
     538                            case $substr_chrs_c_2 == '\f':
     539                                $utf8 .= chr(0x0C);
     540                                ++$c;
     541                                break;
     542                            case $substr_chrs_c_2 == '\r':
     543                                $utf8 .= chr(0x0D);
     544                                ++$c;
     545                                break;
     546
     547                            case $substr_chrs_c_2 == '\\"':
     548                            case $substr_chrs_c_2 == '\\\'':
     549                            case $substr_chrs_c_2 == '\\\\':
     550                            case $substr_chrs_c_2 == '\\/':
     551                                if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
     552                                   ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
     553                                    $utf8 .= $chrs{++$c};
     554                                }
     555                                break;
     556
     557                            case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
     558                                // single, escaped unicode character
     559                                $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
     560                                       . chr(hexdec(substr($chrs, ($c + 4), 2)));
     561                                $utf8 .= $this->utf162utf8($utf16);
     562                                $c += 5;
     563                                break;
     564
     565                            case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
    276566                                $utf8 .= $chrs{$c};
    277    
    278                             }
    279                        
     567                                break;
     568
     569                            case ($ord_chrs_c & 0xE0) == 0xC0:
     570                                // characters U-00000080 - U-000007FF, mask 110XXXXX
     571                                //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     572                                $utf8 .= substr($chrs, $c, 2);
     573                                ++$c;
     574                                break;
     575
     576                            case ($ord_chrs_c & 0xF0) == 0xE0:
     577                                // characters U-00000800 - U-0000FFFF, mask 1110XXXX
     578                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     579                                $utf8 .= substr($chrs, $c, 3);
     580                                $c += 2;
     581                                break;
     582
     583                            case ($ord_chrs_c & 0xF8) == 0xF0:
     584                                // characters U-00010000 - U-001FFFFF, mask 11110XXX
     585                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     586                                $utf8 .= substr($chrs, $c, 4);
     587                                $c += 3;
     588                                break;
     589
     590                            case ($ord_chrs_c & 0xFC) == 0xF8:
     591                                // characters U-00200000 - U-03FFFFFF, mask 111110XX
     592                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     593                                $utf8 .= substr($chrs, $c, 5);
     594                                $c += 4;
     595                                break;
     596
     597                            case ($ord_chrs_c & 0xFE) == 0xFC:
     598                                // characters U-04000000 - U-7FFFFFFF, mask 1111110X
     599                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
     600                                $utf8 .= substr($chrs, $c, 6);
     601                                $c += 5;
     602                                break;
     603
    280604                        }
    281                        
    282                         return $utf8;
    283                    
    284                     } elseif(preg_match('/^\[.*\]$/s', $str) || preg_match('/^{.*}$/s', $str)) { // array, or object notation
    285    
    286                         if($str{0} == '[') {
    287                             $stk = array(JSON_IN_ARR);
    288                             $arr = array();
     605
     606                    }
     607
     608                    return $utf8;
     609
     610                } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
     611                    // array, or object notation
     612
     613                    if ($str{0} == '[') {
     614                        $stk = array(SERVICES_JSON_IN_ARR);
     615                        $arr = array();
     616                    } else {
     617                        if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
     618                            $stk = array(SERVICES_JSON_IN_OBJ);
     619                            $obj = array();
    289620                        } else {
    290                             if($this->use == JSON_LOOSE_TYPE) {
    291                                 $stk = array(JSON_IN_OBJ);
    292                                 $obj = array();
    293                             } else {
    294                                 $stk = array(JSON_IN_OBJ);
    295                                 $obj = new ObjectFromJSON();
    296                             }
     621                            $stk = array(SERVICES_JSON_IN_OBJ);
     622                            $obj = new stdClass();
    297623                        }
    298                        
    299                         array_push($stk, array('what' => JSON_SLICE, 'where' => 0, 'delim' => false));
    300                         $chrs = substr($str, 1, -1);
    301                         $chrs = $this->reduce_string($chrs);
    302                        
    303                         if($chrs == '') {
    304                             if(reset($stk) == JSON_IN_ARR) {
    305                                 return $arr;
     624                    }
    306625
    307                             } else {
    308                                 return $obj;
     626                    array_push($stk, array('what'  => SERVICES_JSON_SLICE,
     627                                           'where' => 0,
     628                                           'delim' => false));
    309629
    310                             }
     630                    $chrs = substr($str, 1, -1);
     631                    $chrs = $this->reduce_string($chrs);
     632
     633                    if ($chrs == '') {
     634                        if (reset($stk) == SERVICES_JSON_IN_ARR) {
     635                            return $arr;
     636
     637                        } else {
     638                            return $obj;
     639
    311640                        }
     641                    }
    312642
    313                         //print("\nparsing {$chrs}\n");
    314                        
    315                         $strlen_chrs = strlen($chrs);
    316                        
    317                         for($c = 0; $c <= $strlen_chrs; $c++) {
    318                        
    319                             $top = end($stk);
    320                             $substr_chrs_c_2 = substr($chrs, $c, 2);
    321                        
    322                             if(($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == JSON_SLICE))) { // found a comma that is not inside a string, array, etc., OR we've reached the end of the character list
    323                                 $slice = substr($chrs, $top['where'], ($c - $top['where']));
    324                                 array_push($stk, array('what' => JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
    325                                 //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
    326    
    327                                 if(reset($stk) == JSON_IN_ARR) { // we are in an array, so just push an element onto the stack
    328                                     array_push($arr, $this->decode($slice));
    329    
    330                                 } elseif(reset($stk) == JSON_IN_OBJ) { // we are in an object, so figure out the property name and set an element in an associative array, for now
    331                                     if(preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { // "name":value pair
    332                                         $key = $this->decode($parts[1]);
    333                                         $val = $this->decode($parts[2]);
     643                    //print("\nparsing {$chrs}\n");
    334644
    335                                         if($this->use == JSON_LOOSE_TYPE) {
    336                                             $obj[$key] = $val;
    337                                         } else {
    338                                             $obj->$key = $val;
    339                                         }
    340                                     } elseif(preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { // name:value pair, where name is unquoted
    341                                         $key = $parts[1];
    342                                         $val = $this->decode($parts[2]);
     645                    $strlen_chrs = strlen($chrs);
    343646
    344                                         if($this->use == JSON_LOOSE_TYPE) {
    345                                             $obj[$key] = $val;
    346                                         } else {
    347                                             $obj->$key = $val;
    348                                         }
     647                    for ($c = 0; $c <= $strlen_chrs; ++$c) {
     648
     649                        $top = end($stk);
     650                        $substr_chrs_c_2 = substr($chrs, $c, 2);
     651
     652                        if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
     653                            // found a comma that is not inside a string, array, etc.,
     654                            // OR we've reached the end of the character list
     655                            $slice = substr($chrs, $top['where'], ($c - $top['where']));
     656                            array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
     657                            //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
     658
     659                            if (reset($stk) == SERVICES_JSON_IN_ARR) {
     660                                // we are in an array, so just push an element onto the stack
     661                                array_push($arr, $this->decode($slice));
     662
     663                            } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
     664                                // we are in an object, so figure
     665                                // out the property name and set an
     666                                // element in an associative array,
     667                                // for now
     668                                $parts = array();
     669                               
     670                                if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
     671                                    // "name":value pair
     672                                    $key = $this->decode($parts[1]);
     673                                    $val = $this->decode($parts[2]);
     674
     675                                    if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
     676                                        $obj[$key] = $val;
     677                                    } else {
     678                                        $obj->$key = $val;
    349679                                    }
    350    
     680                                } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
     681                                    // name:value pair, where name is unquoted
     682                                    $key = $parts[1];
     683                                    $val = $this->decode($parts[2]);
     684
     685                                    if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
     686                                        $obj[$key] = $val;
     687                                    } else {
     688                                        $obj->$key = $val;
     689                                    }
    351690                                }
    352    
    353                             } elseif((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != JSON_IN_STR)) { // found a quote, and we are not inside a string
    354                                 array_push($stk, array('what' => JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
    355                                 //print("Found start of string at {$c}\n");
    356    
    357                             } elseif(($chrs{$c} == $top['delim']) && ($top['what'] == JSON_IN_STR) && (($chrs{$c - 1} != "\\") || ($chrs{$c - 1} == "\\" && $chrs{$c - 2} == "\\"))) { // found a quote, we're in a string, and it's not escaped
    358                                 array_pop($stk);
    359                                 //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
    360    
    361                             } elseif(($chrs{$c} == '[') && in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) { // found a left-bracket, and we are in an array, object, or slice
    362                                 array_push($stk, array('what' => JSON_IN_ARR, 'where' => $c, 'delim' => false));
    363                                 //print("Found start of array at {$c}\n");
    364    
    365                             } elseif(($chrs{$c} == ']') && ($top['what'] == JSON_IN_ARR)) { // found a right-bracket, and we're in an array
    366                                 array_pop($stk);
    367                                 //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
    368    
    369                             } elseif(($chrs{$c} == '{') && in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) { // found a left-brace, and we are in an array, object, or slice
    370                                 array_push($stk, array('what' => JSON_IN_OBJ, 'where' => $c, 'delim' => false));
    371                                 //print("Found start of object at {$c}\n");
    372    
    373                             } elseif(($chrs{$c} == '}') && ($top['what'] == JSON_IN_OBJ)) { // found a right-brace, and we're in an object
    374                                 array_pop($stk);
    375                                 //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
    376    
    377                             } elseif(($substr_chrs_c_2 == '/*') && in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) { // found a comment start, and we are in an array, object, or slice
    378                                 array_push($stk, array('what' => JSON_IN_CMT, 'where' => $c, 'delim' => false));
    379                                 $c++;
    380                                 //print("Found start of comment at {$c}\n");
    381    
    382                             } elseif(($substr_chrs_c_2 == '*/') && ($top['what'] == JSON_IN_CMT)) { // found a comment end, and we're in one now
    383                                 array_pop($stk);
    384                                 $c++;
    385                                
    386                                 for($i = $top['where']; $i <= $c; $i++)
    387                                     $chrs = substr_replace($chrs, ' ', $i, 1);
    388                                
    389                                 //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
    390    
     691
    391692                            }
    392                        
     693
     694                        } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
     695                            // found a quote, and we are not inside a string
     696                            array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
     697                            //print("Found start of string at {$c}\n");
     698
     699                        } elseif (($chrs{$c} == $top['delim']) &&
     700                                 ($top['what'] == SERVICES_JSON_IN_STR) &&
     701                                 ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
     702                            // found a quote, we're in a string, and it's not escaped
     703                            // we know that it's not escaped becase there is _not_ an
     704                            // odd number of backslashes at the end of the string so far
     705                            array_pop($stk);
     706                            //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
     707
     708                        } elseif (($chrs{$c} == '[') &&
     709                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
     710                            // found a left-bracket, and we are in an array, object, or slice
     711                            array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
     712                            //print("Found start of array at {$c}\n");
     713
     714                        } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
     715                            // found a right-bracket, and we're in an array
     716                            array_pop($stk);
     717                            //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
     718
     719                        } elseif (($chrs{$c} == '{') &&
     720                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
     721                            // found a left-brace, and we are in an array, object, or slice
     722                            array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
     723                            //print("Found start of object at {$c}\n");
     724
     725                        } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
     726                            // found a right-brace, and we're in an object
     727                            array_pop($stk);
     728                            //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
     729
     730                        } elseif (($substr_chrs_c_2 == '/*') &&
     731                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
     732                            // found a comment start, and we are in an array, object, or slice
     733                            array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
     734                            $c++;
     735                            //print("Found start of comment at {$c}\n");
     736
     737                        } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
     738                            // found a comment end, and we're in one now
     739                            array_pop($stk);
     740                            $c++;
     741
     742                            for ($i = $top['where']; $i <= $c; ++$i)
     743                                $chrs = substr_replace($chrs, ' ', $i, 1);
     744
     745                            //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
     746
    393747                        }
    394                        
    395                         if(reset($stk) == JSON_IN_ARR) {
    396                             return $arr;
    397    
    398                         } elseif(reset($stk) == JSON_IN_OBJ) {
    399                             return $obj;
    400    
    401                         }
    402                    
     748
    403749                    }
    404             }
     750
     751                    if (reset($stk) == SERVICES_JSON_IN_ARR) {
     752                        return $arr;
     753
     754                    } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
     755                        return $obj;
     756
     757                    }
     758
     759                }
    405760        }
    406        
    407        /** function dec
    408         * alias for decode()
    409         */
    410         function dec($var)
     761    }
     762
     763    /**
     764     * @todo Ultimately, this should just call PEAR::isError()
     765     */
     766    function isError($data, $code = null)
     767    {
     768        if (is_object($data) && (get_class($data) == 'services_json_error' ||
     769                                 is_subclass_of($data, 'services_json_error'))) {
     770            return true;
     771        }
     772
     773        return false;
     774    }
     775}
     776
     777    class Services_JSON_Error
     778    {
     779        function Services_JSON_Error($message = 'unknown error', $code = null,
     780                                     $mode = null, $options = null, $userinfo = null)
    411781        {
    412             return $this->decode($var);
     782
    413783        }
    414        
    415784    }
    416785
    417    /** ObjectFromJSON
    418     * Generic object wrapper, used in object returns from decode()
    419     */
    420     class ObjectFromJSON { function ObjectFromJSON() {} }
     786
    421787   
    422788?>
     789 Pas de fin de ligne à la fin du fichier
  • lib/json/LICENSE

     
    1 --------------------------------------------------------------------
    2                   The PHP License, version 3.0
    3 Copyright (c) 1999 - 2004 The PHP Group. All rights reserved.
    4 --------------------------------------------------------------------
    5 
    6 Redistribution and use in source and binary forms, with or without
    7 modification, is permitted provided that the following conditions
    8 are met:
    9 
    10   1. Redistributions of source code must retain the above copyright
    11      notice, this list of conditions and the following disclaimer.
    12  
    13   2. Redistributions in binary form must reproduce the above copyright
    14      notice, this list of conditions and the following disclaimer in
    15      the documentation and/or other materials provided with the
    16      distribution.
    17  
    18   3. The name "PHP" must not be used to endorse or promote products
    19      derived from this software without prior written permission. For
    20      written permission, please contact group@php.net.
    21  
    22   4. Products derived from this software may not be called "PHP", nor
    23      may "PHP" appear in their name, without prior written permission
    24      from group@php.net.  You may indicate that your software works in
    25      conjunction with PHP by saying "Foo for PHP" instead of calling
    26      it "PHP Foo" or "phpfoo"
    27  
    28   5. The PHP Group may publish revised and/or new versions of the
    29      license from time to time. Each version will be given a
    30      distinguishing version number.
    31      Once covered code has been published under a particular version
    32      of the license, you may always continue to use it under the terms
    33      of that version. You may also choose to use such covered code
    34      under the terms of any subsequent version of the license
    35      published by the PHP Group. No one other than the PHP Group has
    36      the right to modify the terms applicable to covered code created
    37      under this License.
    38 
    39   6. Redistributions of any form whatsoever must retain the following
    40      acknowledgment:
    41      "This product includes PHP, freely available from
    42      <http://www.php.net/>".
    43 
    44 THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
    45 ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    46 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    47 PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE PHP
    48 DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
    49 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    50 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    51 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    52 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    53 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    54 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
    55 OF THE POSSIBILITY OF SUCH DAMAGE.
    56 
    57 --------------------------------------------------------------------
    58 
    59 This software consists of voluntary contributions made by many
    60 individuals on behalf of the PHP Group.
    61 
    62 The PHP Group can be contacted via Email at group@php.net.
    63 
    64 For more information on the PHP Group and the PHP project,
    65 please see <http://www.php.net>.
    66 
    67 This product includes the Zend Engine, freely available at
    68 <http://www.zend.com>.
     1SEE http://www.opensource.org/licenses/bsd-license.php
     2 Pas de fin de ligne à la fin du fichier
  • lib/jelix/utils/jJsonRpc.class.php

     
    33* @package     jelix
    44* @subpackage  utils
    55* @author      Laurent Jouanneau
    6 * @contributor
     6* @contributor Julien ISSLER
    77* @copyright   2005-2007 Laurent Jouanneau
     8* @copyright   2007 Julien Issler
    89* @link        http://www.jelix.org
    910* @licence     GNU Lesser General Public Licence see LICENCE file or http://www.gnu.org/licenses/lgpl.html
    1011*/
     
    3536#if ENABLE_PHP_JSON
    3637        $obj = json_decode($content,true);
    3738#else
    38         $json = new JSON(JSON_LOOSE_TYPE);
     39        $json = new SERVICES_JSON(SERVICES_JSON_LOOSE_TYPE);
    3940        $obj = $json->decode($content);
    4041        /*
    4142        $obj->method
     
    5657#if ENABLE_PHP_JSON
    5758        return '{"method":"'.$methodname.'","params":'.json_encode($params).',"id":'.json_encode($id).'}';
    5859#else
    59         $json = new JSON();
     60        $json = new SERVICES_JSON();
    6061        return '{"method":"'.$methodname.'","params":'.$json->encode($params).',"id":'.$json->encode($id).'}';
    6162#endif
    6263
     
    7273#if ENABLE_PHP_JSON
    7374        return json_decode($content);
    7475#else
    75         $json = new JSON(JSON_LOOSE_TYPE);
     76        $json = new SERVICES_JSON(SERVICES_JSON_LOOSE_TYPE);
    7677        return $json->decode($content);
    7778#endif
    7879
     
    8788#if ENABLE_PHP_JSON
    8889        return '{"result":'.json_encode($params).',"error":null,"id":'.json_encode($id).'}';
    8990#else
    90         $json = new JSON();
     91        $json = new SERVICES_JSON();
    9192        return '{"result":'.$json->encode($params).',"error":null,"id":'.$json->encode($id).'}';
    9293#endif
    9394    }
     
    102103#if ENABLE_PHP_JSON
    103104        return '{"result":null,"error":{"code": '.json_encode($code).', "string":'.json_encode($message).' },"id":'.json_encode($id).'}';
    104105#else
    105         $json = new JSON();
     106        $json = new SERVICES_JSON();
    106107        return '{"result":null,"error":{"code": '.$json->encode($code).', "string":'.$json->encode($message).' },"id":'.$json->encode($id).'}';
    107108#endif
    108109    }