r56136 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r56135‎ | r56136 | r56137 >
Date:14:33, 10 September 2009
Author:dale
Status:resolved (Comments)
Tags:
Comment:
more (bug 20336)
* added json folder
* moved Services_JSON.php there
* moved Format JSON into its own class
* updated AutoLoader
Modified paths:
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/GlobalFunctions.php (modified) (history)
  • /trunk/phase3/includes/HttpFunctions.php (modified) (history)
  • /trunk/phase3/includes/OutputPage.php (modified) (history)
  • /trunk/phase3/includes/api/ApiFormatJson_json.php (deleted) (history)
  • /trunk/phase3/includes/json (added) (history)
  • /trunk/phase3/includes/json/FormatJson.php (added) (history)
  • /trunk/phase3/includes/json/Services_JSON.php (added) (history)
  • /trunk/phase3/js2/mwEmbed/php/languages/mwEmbed.i18n.php (modified) (history)
  • /trunk/phase3/js2/mwEmbed/php/maintenance/mergeJavascriptMsg.php (modified) (history)
  • /trunk/phase3/js2/mwEmbed/skins/ctrlBuilder.js (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/json/Services_JSON.php
@@ -0,0 +1,862 @@
 2+<?php
 3+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 4+
 5+/**
 6+* Converts to and from JSON format.
 7+*
 8+* JSON (JavaScript Object Notation) is a lightweight data-interchange
 9+* format. It is easy for humans to read and write. It is easy for machines
 10+* to parse and generate. It is based on a subset of the JavaScript
 11+* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
 12+* This feature can also be found in Python. JSON is a text format that is
 13+* completely language independent but uses conventions that are familiar
 14+* to programmers of the C-family of languages, including C, C++, C#, Java,
 15+* JavaScript, Perl, TCL, and many others. These properties make JSON an
 16+* ideal data-interchange language.
 17+*
 18+* This package provides a simple encoder and decoder for JSON notation. It
 19+* is intended for use with client-side Javascript applications that make
 20+* use of HTTPRequest to perform server communication functions - data can
 21+* be encoded into JSON notation for use in a client-side javascript, or
 22+* decoded from incoming Javascript requests. JSON format is native to
 23+* Javascript, and can be directly eval()'ed with no further parsing
 24+* overhead
 25+*
 26+* All strings should be in ASCII or UTF-8 format!
 27+*
 28+* LICENSE: Redistribution and use in source and binary forms, with or
 29+* without modification, are permitted provided that the following
 30+* conditions are met: Redistributions of source code must retain the
 31+* above copyright notice, this list of conditions and the following
 32+* disclaimer. Redistributions in binary form must reproduce the above
 33+* copyright notice, this list of conditions and the following disclaimer
 34+* in the documentation and/or other materials provided with the
 35+* distribution.
 36+*
 37+* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 38+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 39+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 40+* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 41+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 42+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 43+* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 44+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 45+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 46+* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 47+* DAMAGE.
 48+*
 49+* @ingroup API
 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$
 55+* @license http://www.opensource.org/licenses/bsd-license.php
 56+* @see 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+*/
 62+define('SERVICES_JSON_SLICE', 1);
 63+
 64+/**
 65+* Marker constant for Services_JSON::decode(), used to flag stack state
 66+*/
 67+define('SERVICES_JSON_IN_STR', 2);
 68+
 69+/**
 70+* Marker constant for Services_JSON::decode(), used to flag stack state
 71+*/
 72+define('SERVICES_JSON_IN_ARR', 3);
 73+
 74+/**
 75+* Marker constant for Services_JSON::decode(), used to flag stack state
 76+*/
 77+define('SERVICES_JSON_IN_OBJ', 4);
 78+
 79+/**
 80+* Marker constant for Services_JSON::decode(), used to flag stack state
 81+*/
 82+define('SERVICES_JSON_IN_CMT', 5);
 83+
 84+/**
 85+* Behavior switch for Services_JSON::decode()
 86+*/
 87+define('SERVICES_JSON_LOOSE_TYPE', 16);
 88+
 89+/**
 90+* Behavior switch for Services_JSON::decode()
 91+*/
 92+define('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+ *
 115+ * @ingroup API
 116+ */
 117+class Services_JSON
 118+{
 119+ /**
 120+ * constructs a new JSON instance
 121+ *
 122+ * @param int $use object behavior flags; combine with boolean-OR
 123+ *
 124+ * possible values:
 125+ * - SERVICES_JSON_LOOSE_TYPE: loose typing.
 126+ * "{...}" syntax creates associative arrays
 127+ * instead of objects in decode().
 128+ * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
 129+ * Values which can't be encoded (e.g. resources)
 130+ * appear as NULL instead of throwing errors.
 131+ * By default, a deeply-nested resource will
 132+ * bubble up with an error, so all return values
 133+ * from encode() should be checked with isError()
 134+ */
 135+ function Services_JSON($use = 0)
 136+ {
 137+ $this->use = $use;
 138+ }
 139+
 140+ /**
 141+ * convert a string from one UTF-16 char to one UTF-8 char
 142+ *
 143+ * Normally should be handled by mb_convert_encoding, but
 144+ * provides a slower PHP-only method for installations
 145+ * that lack the multibye string extension.
 146+ *
 147+ * @param string $utf16 UTF-16 character
 148+ * @return string UTF-8 character
 149+ * @access private
 150+ */
 151+ function utf162utf8($utf16)
 152+ {
 153+ // oh please oh please oh please oh please oh please
 154+ if(function_exists('mb_convert_encoding')) {
 155+ return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
 156+ }
 157+
 158+ $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
 159+
 160+ switch(true) {
 161+ case ((0x7F & $bytes) == $bytes):
 162+ // this case should never be reached, because we are in ASCII range
 163+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 164+ return chr(0x7F & $bytes);
 165+
 166+ case (0x07FF & $bytes) == $bytes:
 167+ // return a 2-byte UTF-8 character
 168+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 169+ return chr(0xC0 | (($bytes >> 6) & 0x1F))
 170+ . chr(0x80 | ($bytes & 0x3F));
 171+
 172+ case (0xFC00 & $bytes) == 0xD800 && strlen($utf16) >= 4 && (0xFC & ord($utf16{2})) == 0xDC:
 173+ // return a 4-byte UTF-8 character
 174+ $char = ((($bytes & 0x03FF) << 10)
 175+ | ((ord($utf16{2}) & 0x03) << 8)
 176+ | ord($utf16{3}));
 177+ $char += 0x10000;
 178+ return chr(0xF0 | (($char >> 18) & 0x07))
 179+ . chr(0x80 | (($char >> 12) & 0x3F))
 180+ . chr(0x80 | (($char >> 6) & 0x3F))
 181+ . chr(0x80 | ($char & 0x3F));
 182+
 183+ case (0xFFFF & $bytes) == $bytes:
 184+ // return a 3-byte UTF-8 character
 185+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 186+ return chr(0xE0 | (($bytes >> 12) & 0x0F))
 187+ . chr(0x80 | (($bytes >> 6) & 0x3F))
 188+ . chr(0x80 | ($bytes & 0x3F));
 189+ }
 190+
 191+ // ignoring UTF-32 for now, sorry
 192+ return '';
 193+ }
 194+
 195+ /**
 196+ * convert a string from one UTF-8 char to one UTF-16 char
 197+ *
 198+ * Normally should be handled by mb_convert_encoding, but
 199+ * provides a slower PHP-only method for installations
 200+ * that lack the multibye string extension.
 201+ *
 202+ * @param string $utf8 UTF-8 character
 203+ * @return string UTF-16 character
 204+ * @access private
 205+ */
 206+ function utf82utf16($utf8)
 207+ {
 208+ // oh please oh please oh please oh please oh please
 209+ if(function_exists('mb_convert_encoding')) {
 210+ return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
 211+ }
 212+
 213+ switch(strlen($utf8)) {
 214+ case 1:
 215+ // this case should never be reached, because we are in ASCII range
 216+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 217+ return $utf8;
 218+
 219+ case 2:
 220+ // return a UTF-16 character from a 2-byte UTF-8 char
 221+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 222+ return chr(0x07 & (ord($utf8{0}) >> 2))
 223+ . chr((0xC0 & (ord($utf8{0}) << 6))
 224+ | (0x3F & ord($utf8{1})));
 225+
 226+ case 3:
 227+ // return a UTF-16 character from a 3-byte UTF-8 char
 228+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 229+ return chr((0xF0 & (ord($utf8{0}) << 4))
 230+ | (0x0F & (ord($utf8{1}) >> 2)))
 231+ . chr((0xC0 & (ord($utf8{1}) << 6))
 232+ | (0x7F & ord($utf8{2})));
 233+
 234+ case 4:
 235+ // return a UTF-16 surrogate pair from a 4-byte UTF-8 char
 236+ if(ord($utf8{0}) > 0xF4) return ''; # invalid
 237+ $char = ((0x1C0000 & (ord($utf8{0}) << 18))
 238+ | (0x03F000 & (ord($utf8{1}) << 12))
 239+ | (0x000FC0 & (ord($utf8{2}) << 6))
 240+ | (0x00003F & ord($utf8{3})));
 241+ if($char > 0x10FFFF) return ''; # invalid
 242+ $char -= 0x10000;
 243+ return chr(0xD8 | (($char >> 18) & 0x03))
 244+ . chr(($char >> 10) & 0xFF)
 245+ . chr(0xDC | (($char >> 8) & 0x03))
 246+ . chr($char & 0xFF);
 247+ }
 248+
 249+ // ignoring UTF-32 for now, sorry
 250+ return '';
 251+ }
 252+
 253+ /**
 254+ * encodes an arbitrary variable into JSON format
 255+ *
 256+ * @param mixed $var any number, boolean, string, array, or object to be encoded.
 257+ * see argument 1 to Services_JSON() above for array-parsing behavior.
 258+ * if var is a strng, note that encode() always expects it
 259+ * to be in ASCII or UTF-8 format!
 260+ * @param bool $pretty pretty-print output with indents and newlines
 261+ *
 262+ * @return mixed JSON string representation of input var or an error if a problem occurs
 263+ * @access public
 264+ */
 265+ function encode($var, $pretty=false)
 266+ {
 267+ $this->indent = 0;
 268+ $this->pretty = $pretty;
 269+ $this->nameValSeparator = $pretty ? ': ' : ':';
 270+ return $this->encode2($var);
 271+ }
 272+
 273+ /**
 274+ * encodes an arbitrary variable into JSON format
 275+ *
 276+ * @param mixed $var any number, boolean, string, array, or object to be encoded.
 277+ * see argument 1 to Services_JSON() above for array-parsing behavior.
 278+ * if var is a strng, note that encode() always expects it
 279+ * to be in ASCII or UTF-8 format!
 280+ *
 281+ * @return mixed JSON string representation of input var or an error if a problem occurs
 282+ * @access private
 283+ */
 284+ function encode2($var)
 285+ {
 286+ if ($this->pretty) {
 287+ $close = "\n" . str_repeat("\t", $this->indent);
 288+ $open = $close . "\t";
 289+ $mid = ',' . $open;
 290+ }
 291+ else {
 292+ $open = $close = '';
 293+ $mid = ',';
 294+ }
 295+
 296+ switch (gettype($var)) {
 297+ case 'boolean':
 298+ return $var ? 'true' : 'false';
 299+
 300+ case 'NULL':
 301+ return 'null';
 302+
 303+ case 'integer':
 304+ return (int) $var;
 305+
 306+ case 'double':
 307+ case 'float':
 308+ return (float) $var;
 309+
 310+ case 'string':
 311+ // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
 312+ $ascii = '';
 313+ $strlen_var = strlen($var);
 314+
 315+ /*
 316+ * Iterate over every character in the string,
 317+ * escaping with a slash or encoding to UTF-8 where necessary
 318+ */
 319+ for ($c = 0; $c < $strlen_var; ++$c) {
 320+
 321+ $ord_var_c = ord($var{$c});
 322+
 323+ switch (true) {
 324+ case $ord_var_c == 0x08:
 325+ $ascii .= '\b';
 326+ break;
 327+ case $ord_var_c == 0x09:
 328+ $ascii .= '\t';
 329+ break;
 330+ case $ord_var_c == 0x0A:
 331+ $ascii .= '\n';
 332+ break;
 333+ case $ord_var_c == 0x0C:
 334+ $ascii .= '\f';
 335+ break;
 336+ case $ord_var_c == 0x0D:
 337+ $ascii .= '\r';
 338+ break;
 339+
 340+ case $ord_var_c == 0x22:
 341+ case $ord_var_c == 0x2F:
 342+ case $ord_var_c == 0x5C:
 343+ // double quote, slash, slosh
 344+ $ascii .= '\\'.$var{$c};
 345+ break;
 346+
 347+ case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
 348+ // characters U-00000000 - U-0000007F (same as ASCII)
 349+ $ascii .= $var{$c};
 350+ break;
 351+
 352+ case (($ord_var_c & 0xE0) == 0xC0):
 353+ // characters U-00000080 - U-000007FF, mask 110XXXXX
 354+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 355+ $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
 356+ $c += 1;
 357+ $utf16 = $this->utf82utf16($char);
 358+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
 359+ break;
 360+
 361+ case (($ord_var_c & 0xF0) == 0xE0):
 362+ // characters U-00000800 - U-0000FFFF, mask 1110XXXX
 363+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 364+ $char = pack('C*', $ord_var_c,
 365+ ord($var{$c + 1}),
 366+ ord($var{$c + 2}));
 367+ $c += 2;
 368+ $utf16 = $this->utf82utf16($char);
 369+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
 370+ break;
 371+
 372+ case (($ord_var_c & 0xF8) == 0xF0):
 373+ // characters U-00010000 - U-001FFFFF, mask 11110XXX
 374+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 375+ // These will always return a surrogate pair
 376+ $char = pack('C*', $ord_var_c,
 377+ ord($var{$c + 1}),
 378+ ord($var{$c + 2}),
 379+ ord($var{$c + 3}));
 380+ $c += 3;
 381+ $utf16 = $this->utf82utf16($char);
 382+ if($utf16 == '') {
 383+ $ascii .= '\ufffd';
 384+ } else {
 385+ $utf16 = str_split($utf16, 2);
 386+ $ascii .= sprintf('\u%04s\u%04s', bin2hex($utf16[0]), bin2hex($utf16[1]));
 387+ }
 388+ break;
 389+ }
 390+ }
 391+
 392+ return '"'.$ascii.'"';
 393+
 394+ case 'array':
 395+ /*
 396+ * As per JSON spec if any array key is not an integer
 397+ * we must treat the the whole array as an object. We
 398+ * also try to catch a sparsely populated associative
 399+ * array with numeric keys here because some JS engines
 400+ * will create an array with empty indexes up to
 401+ * max_index which can cause memory issues and because
 402+ * the keys, which may be relevant, will be remapped
 403+ * otherwise.
 404+ *
 405+ * As per the ECMA and JSON specification an object may
 406+ * have any string as a property. Unfortunately due to
 407+ * a hole in the ECMA specification if the key is a
 408+ * ECMA reserved word or starts with a digit the
 409+ * parameter is only accessible using ECMAScript's
 410+ * bracket notation.
 411+ */
 412+
 413+ // treat as a JSON object
 414+ if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
 415+ $this->indent++;
 416+ $properties = array_map(array($this, 'name_value'),
 417+ array_keys($var),
 418+ array_values($var));
 419+ $this->indent--;
 420+
 421+ foreach($properties as $property) {
 422+ if(Services_JSON::isError($property)) {
 423+ return $property;
 424+ }
 425+ }
 426+
 427+ return '{' . $open . join($mid, $properties) . $close . '}';
 428+ }
 429+
 430+ // treat it like a regular array
 431+ $this->indent++;
 432+ $elements = array_map(array($this, 'encode2'), $var);
 433+ $this->indent--;
 434+
 435+ foreach($elements as $element) {
 436+ if(Services_JSON::isError($element)) {
 437+ return $element;
 438+ }
 439+ }
 440+
 441+ return '[' . $open . join($mid, $elements) . $close . ']';
 442+
 443+ case 'object':
 444+ $vars = get_object_vars($var);
 445+
 446+ $this->indent++;
 447+ $properties = array_map(array($this, 'name_value'),
 448+ array_keys($vars),
 449+ array_values($vars));
 450+ $this->indent--;
 451+
 452+ foreach($properties as $property) {
 453+ if(Services_JSON::isError($property)) {
 454+ return $property;
 455+ }
 456+ }
 457+
 458+ return '{' . $open . join($mid, $properties) . $close . '}';
 459+
 460+ default:
 461+ return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
 462+ ? 'null'
 463+ : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
 464+ }
 465+ }
 466+
 467+ /**
 468+ * array-walking function for use in generating JSON-formatted name-value pairs
 469+ *
 470+ * @param string $name name of key to use
 471+ * @param mixed $value reference to an array element to be encoded
 472+ *
 473+ * @return string JSON-formatted name-value pair, like '"name":value'
 474+ * @access private
 475+ */
 476+ function name_value($name, $value)
 477+ {
 478+ $encoded_value = $this->encode2($value);
 479+
 480+ if(Services_JSON::isError($encoded_value)) {
 481+ return $encoded_value;
 482+ }
 483+
 484+ return $this->encode2(strval($name)) . $this->nameValSeparator . $encoded_value;
 485+ }
 486+
 487+ /**
 488+ * reduce a string by removing leading and trailing comments and whitespace
 489+ *
 490+ * @param $str string string value to strip of comments and whitespace
 491+ *
 492+ * @return string string value stripped of comments and whitespace
 493+ * @access private
 494+ */
 495+ function reduce_string($str)
 496+ {
 497+ $str = preg_replace(array(
 498+
 499+ // eliminate single line comments in '// ...' form
 500+ '#^\s*//(.+)$#m',
 501+
 502+ // eliminate multi-line comments in '/* ... */' form, at start of string
 503+ '#^\s*/\*(.+)\*/#Us',
 504+
 505+ // eliminate multi-line comments in '/* ... */' form, at end of string
 506+ '#/\*(.+)\*/\s*$#Us'
 507+
 508+ ), '', $str);
 509+
 510+ // eliminate extraneous space
 511+ return trim($str);
 512+ }
 513+
 514+ /**
 515+ * decodes a JSON string into appropriate variable
 516+ *
 517+ * @param string $str JSON-formatted string
 518+ *
 519+ * @return mixed number, boolean, string, array, or object
 520+ * corresponding to given JSON input string.
 521+ * See argument 1 to Services_JSON() above for object-output behavior.
 522+ * Note that decode() always returns strings
 523+ * in ASCII or UTF-8 format!
 524+ * @access public
 525+ */
 526+ function decode($str)
 527+ {
 528+ $str = $this->reduce_string($str);
 529+
 530+ switch (strtolower($str)) {
 531+ case 'true':
 532+ return true;
 533+
 534+ case 'false':
 535+ return false;
 536+
 537+ case 'null':
 538+ return null;
 539+
 540+ default:
 541+ $m = array();
 542+
 543+ if (is_numeric($str)) {
 544+ // Lookie-loo, it's a number
 545+
 546+ // This would work on its own, but I'm trying to be
 547+ // good about returning integers where appropriate:
 548+ // return (float)$str;
 549+
 550+ // Return float or int, as appropriate
 551+ return ((float)$str == (integer)$str)
 552+ ? (integer)$str
 553+ : (float)$str;
 554+
 555+ } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
 556+ // STRINGS RETURNED IN UTF-8 FORMAT
 557+ $delim = substr($str, 0, 1);
 558+ $chrs = substr($str, 1, -1);
 559+ $utf8 = '';
 560+ $strlen_chrs = strlen($chrs);
 561+
 562+ for ($c = 0; $c < $strlen_chrs; ++$c) {
 563+
 564+ $substr_chrs_c_2 = substr($chrs, $c, 2);
 565+ $ord_chrs_c = ord($chrs{$c});
 566+
 567+ switch (true) {
 568+ case $substr_chrs_c_2 == '\b':
 569+ $utf8 .= chr(0x08);
 570+ ++$c;
 571+ break;
 572+ case $substr_chrs_c_2 == '\t':
 573+ $utf8 .= chr(0x09);
 574+ ++$c;
 575+ break;
 576+ case $substr_chrs_c_2 == '\n':
 577+ $utf8 .= chr(0x0A);
 578+ ++$c;
 579+ break;
 580+ case $substr_chrs_c_2 == '\f':
 581+ $utf8 .= chr(0x0C);
 582+ ++$c;
 583+ break;
 584+ case $substr_chrs_c_2 == '\r':
 585+ $utf8 .= chr(0x0D);
 586+ ++$c;
 587+ break;
 588+
 589+ case $substr_chrs_c_2 == '\\"':
 590+ case $substr_chrs_c_2 == '\\\'':
 591+ case $substr_chrs_c_2 == '\\\\':
 592+ case $substr_chrs_c_2 == '\\/':
 593+ if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
 594+ ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
 595+ $utf8 .= $chrs{++$c};
 596+ }
 597+ break;
 598+
 599+ case preg_match('/\\\uD[89AB][0-9A-F]{2}\\\uD[C-F][0-9A-F]{2}/i', substr($chrs, $c, 12)):
 600+ // escaped unicode surrogate pair
 601+ $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
 602+ . chr(hexdec(substr($chrs, ($c + 4), 2)))
 603+ . chr(hexdec(substr($chrs, ($c + 8), 2)))
 604+ . chr(hexdec(substr($chrs, ($c + 10), 2)));
 605+ $utf8 .= $this->utf162utf8($utf16);
 606+ $c += 11;
 607+ break;
 608+
 609+ case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
 610+ // single, escaped unicode character
 611+ $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
 612+ . chr(hexdec(substr($chrs, ($c + 4), 2)));
 613+ $utf8 .= $this->utf162utf8($utf16);
 614+ $c += 5;
 615+ break;
 616+
 617+ case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
 618+ $utf8 .= $chrs{$c};
 619+ break;
 620+
 621+ case ($ord_chrs_c & 0xE0) == 0xC0:
 622+ // characters U-00000080 - U-000007FF, mask 110XXXXX
 623+ //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 624+ $utf8 .= substr($chrs, $c, 2);
 625+ ++$c;
 626+ break;
 627+
 628+ case ($ord_chrs_c & 0xF0) == 0xE0:
 629+ // characters U-00000800 - U-0000FFFF, mask 1110XXXX
 630+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 631+ $utf8 .= substr($chrs, $c, 3);
 632+ $c += 2;
 633+ break;
 634+
 635+ case ($ord_chrs_c & 0xF8) == 0xF0:
 636+ // characters U-00010000 - U-001FFFFF, mask 11110XXX
 637+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 638+ $utf8 .= substr($chrs, $c, 4);
 639+ $c += 3;
 640+ break;
 641+
 642+ case ($ord_chrs_c & 0xFC) == 0xF8:
 643+ // characters U-00200000 - U-03FFFFFF, mask 111110XX
 644+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 645+ $utf8 .= substr($chrs, $c, 5);
 646+ $c += 4;
 647+ break;
 648+
 649+ case ($ord_chrs_c & 0xFE) == 0xFC:
 650+ // characters U-04000000 - U-7FFFFFFF, mask 1111110X
 651+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
 652+ $utf8 .= substr($chrs, $c, 6);
 653+ $c += 5;
 654+ break;
 655+
 656+ }
 657+
 658+ }
 659+
 660+ return $utf8;
 661+
 662+ } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
 663+ // array, or object notation
 664+
 665+ if ($str{0} == '[') {
 666+ $stk = array(SERVICES_JSON_IN_ARR);
 667+ $arr = array();
 668+ } else {
 669+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
 670+ $stk = array(SERVICES_JSON_IN_OBJ);
 671+ $obj = array();
 672+ } else {
 673+ $stk = array(SERVICES_JSON_IN_OBJ);
 674+ $obj = new stdClass();
 675+ }
 676+ }
 677+
 678+ array_push($stk, array( 'what' => SERVICES_JSON_SLICE,
 679+ 'where' => 0,
 680+ 'delim' => false));
 681+
 682+ $chrs = substr($str, 1, -1);
 683+ $chrs = $this->reduce_string($chrs);
 684+
 685+ if ($chrs == '') {
 686+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
 687+ return $arr;
 688+
 689+ } else {
 690+ return $obj;
 691+
 692+ }
 693+ }
 694+
 695+ //print("\nparsing {$chrs}\n");
 696+
 697+ $strlen_chrs = strlen($chrs);
 698+
 699+ for ($c = 0; $c <= $strlen_chrs; ++$c) {
 700+
 701+ $top = end($stk);
 702+ $substr_chrs_c_2 = substr($chrs, $c, 2);
 703+
 704+ if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
 705+ // found a comma that is not inside a string, array, etc.,
 706+ // OR we've reached the end of the character list
 707+ $slice = substr($chrs, $top['where'], ($c - $top['where']));
 708+ array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
 709+ //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
 710+
 711+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
 712+ // we are in an array, so just push an element onto the stack
 713+ array_push($arr, $this->decode($slice));
 714+
 715+ } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
 716+ // we are in an object, so figure
 717+ // out the property name and set an
 718+ // element in an associative array,
 719+ // for now
 720+ $parts = array();
 721+
 722+ if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
 723+ // "name":value pair
 724+ $key = $this->decode($parts[1]);
 725+ $val = $this->decode($parts[2]);
 726+
 727+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
 728+ $obj[$key] = $val;
 729+ } else {
 730+ $obj->$key = $val;
 731+ }
 732+ } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
 733+ // name:value pair, where name is unquoted
 734+ $key = $parts[1];
 735+ $val = $this->decode($parts[2]);
 736+
 737+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
 738+ $obj[$key] = $val;
 739+ } else {
 740+ $obj->$key = $val;
 741+ }
 742+ }
 743+
 744+ }
 745+
 746+ } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
 747+ // found a quote, and we are not inside a string
 748+ array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
 749+ //print("Found start of string at {$c}\n");
 750+
 751+ } elseif (($chrs{$c} == $top['delim']) &&
 752+ ($top['what'] == SERVICES_JSON_IN_STR) &&
 753+ (($chrs{$c - 1} != '\\') ||
 754+ ($chrs{$c - 1} == '\\' && $chrs{$c - 2} == '\\'))) {
 755+ // found a quote, we're in a string, and it's not escaped
 756+ array_pop($stk);
 757+ //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
 758+
 759+ } elseif (($chrs{$c} == '[') &&
 760+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
 761+ // found a left-bracket, and we are in an array, object, or slice
 762+ array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
 763+ //print("Found start of array at {$c}\n");
 764+
 765+ } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
 766+ // found a right-bracket, and we're in an array
 767+ array_pop($stk);
 768+ //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
 769+
 770+ } elseif (($chrs{$c} == '{') &&
 771+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
 772+ // found a left-brace, and we are in an array, object, or slice
 773+ array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
 774+ //print("Found start of object at {$c}\n");
 775+
 776+ } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
 777+ // found a right-brace, and we're in an object
 778+ array_pop($stk);
 779+ //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
 780+
 781+ } elseif (($substr_chrs_c_2 == '/*') &&
 782+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
 783+ // found a comment start, and we are in an array, object, or slice
 784+ array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
 785+ $c++;
 786+ //print("Found start of comment at {$c}\n");
 787+
 788+ } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
 789+ // found a comment end, and we're in one now
 790+ array_pop($stk);
 791+ $c++;
 792+
 793+ for ($i = $top['where']; $i <= $c; ++$i)
 794+ $chrs = substr_replace($chrs, ' ', $i, 1);
 795+
 796+ //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
 797+
 798+ }
 799+
 800+ }
 801+
 802+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
 803+ return $arr;
 804+
 805+ } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
 806+ return $obj;
 807+
 808+ }
 809+
 810+ }
 811+ }
 812+ }
 813+
 814+ /**
 815+ * @todo Ultimately, this should just call PEAR::isError()
 816+ */
 817+ function isError($data, $code = null)
 818+ {
 819+ if (class_exists('pear')) {
 820+ //avoid some strict warnings on PEAR isError check (looks like http://pear.php.net/bugs/bug.php?id=9950 has been around for some time)
 821+ return @PEAR::isError($data, $code);
 822+ } elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
 823+ is_subclass_of($data, 'services_json_error'))) {
 824+ return true;
 825+ }
 826+
 827+ return false;
 828+ }
 829+}
 830+
 831+
 832+// Hide the PEAR_Error variant from Doxygen
 833+/// @cond
 834+if (class_exists('PEAR_Error')) {
 835+
 836+ /**
 837+ * @ingroup API
 838+ */
 839+ class Services_JSON_Error extends PEAR_Error
 840+ {
 841+ function Services_JSON_Error($message = 'unknown error', $code = null,
 842+ $mode = null, $options = null, $userinfo = null)
 843+ {
 844+ parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
 845+ }
 846+ }
 847+
 848+} else {
 849+/// @endcond
 850+
 851+ /**
 852+ * @todo Ultimately, this class shall be descended from PEAR_Error
 853+ * @ingroup API
 854+ */
 855+ class Services_JSON_Error
 856+ {
 857+ function Services_JSON_Error($message = 'unknown error', $code = null,
 858+ $mode = null, $options = null, $userinfo = null)
 859+ {
 860+
 861+ }
 862+ }
 863+}
Property changes on: trunk/phase3/includes/json/Services_JSON.php
___________________________________________________________________
Name: svn:keywords
1864 + Id
Name: svn:mergeinfo
2865 + /branches/REL1_15/phase3/includes/api/ApiFormatJson_json.php:51646
/branches/wmf-deployment/includes/api/ApiFormatJson_json.php:53381
Name: svn:eol-style
3866 + native
Index: trunk/phase3/includes/json/FormatJson.php
@@ -0,0 +1,33 @@
 2+<?
 3+/*
 4+ * simple wrapper for json_econde and json_decode that falls back on Services_JSON class
 5+ */
 6+if( !(defined( 'MEDIAWIKI' ) ) ) {
 7+ die( 1 );
 8+}
 9+
 10+class FormatJson{
 11+ public static function encode($value, $isHtml=false){
 12+ // Some versions of PHP have a broken json_encode, see PHP bug
 13+ // 46944. Test encoding an affected character (U+20000) to
 14+ // avoid this.
 15+ if (!function_exists('json_encode') || $isHtml || strtolower(json_encode("\xf0\xa0\x80\x80")) != '\ud840\udc00') {
 16+ $json = new Services_JSON();
 17+ return $json->encode($value, $isHtml) ;
 18+ } else {
 19+ return json_encode($value);
 20+ }
 21+ }
 22+ public static function decode($value, $assoc=false){
 23+ if (!function_exists('json_decode') ) {
 24+ $json = new Services_JSON();
 25+ $jsonDec = $json->decode($value);
 26+ if($assoc)
 27+ $jsonDec = (array) $jsonDec;
 28+ return $jsonDec;
 29+ } else {
 30+ return json_decode($value, $assoc);
 31+ }
 32+ }
 33+}
 34+?>
\ No newline at end of file
Index: trunk/phase3/includes/GlobalFunctions.php
@@ -3342,28 +3342,4 @@
33433343 }
33443344 $langCode = implode ( '-' , $codeBCP );
33453345 return $langCode;
3346 -}
3347 -class FormatJson{
3348 - public static function encode($value, $isHtml=false){
3349 - // Some versions of PHP have a broken json_encode, see PHP bug
3350 - // 46944. Test encoding an affected character (U+20000) to
3351 - // avoid this.
3352 - if (!function_exists('json_encode') || $isHtml || strtolower(json_encode("\xf0\xa0\x80\x80")) != '\ud840\udc00') {
3353 - $json = new Services_JSON();
3354 - return $json->encode($value, $isHtml) ;
3355 - } else {
3356 - return json_encode($value);
3357 - }
3358 - }
3359 - public static function decode($value, $assoc=false){
3360 - if (!function_exists('json_decode') ) {
3361 - $json = new Services_JSON();
3362 - $jsonDec = $json->decode($value);
3363 - if($assoc)
3364 - $jsonDec = (array) $jsonDec;
3365 - return $jsonDec;
3366 - } else {
3367 - return json_decode($value, $assoc);
3368 - }
3369 - }
33703346 }
\ No newline at end of file
Index: trunk/phase3/includes/OutputPage.php
@@ -16,7 +16,7 @@
1717
1818 var $mScriptLoaderClassList = array();
1919
20 - // The most recent revision ID of any script that is grouped in the script request
 20+ // The most recent revision ID of any wikiPage script that is grouped in the script request
2121 var $mLatestScriptRevID = 0;
2222
2323 var $mScripts = '', $mLinkColours, $mPageLinkTitle = '', $mHeadItems = array();
Index: trunk/phase3/includes/api/ApiFormatJson_json.php
@@ -1,862 +0,0 @@
2 -<?php
3 -/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4 -
5 -/**
6 -* Converts to and from JSON format.
7 -*
8 -* JSON (JavaScript Object Notation) is a lightweight data-interchange
9 -* format. It is easy for humans to read and write. It is easy for machines
10 -* to parse and generate. It is based on a subset of the JavaScript
11 -* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
12 -* This feature can also be found in Python. JSON is a text format that is
13 -* completely language independent but uses conventions that are familiar
14 -* to programmers of the C-family of languages, including C, C++, C#, Java,
15 -* JavaScript, Perl, TCL, and many others. These properties make JSON an
16 -* ideal data-interchange language.
17 -*
18 -* This package provides a simple encoder and decoder for JSON notation. It
19 -* is intended for use with client-side Javascript applications that make
20 -* use of HTTPRequest to perform server communication functions - data can
21 -* be encoded into JSON notation for use in a client-side javascript, or
22 -* decoded from incoming Javascript requests. JSON format is native to
23 -* Javascript, and can be directly eval()'ed with no further parsing
24 -* overhead
25 -*
26 -* All strings should be in ASCII or UTF-8 format!
27 -*
28 -* LICENSE: Redistribution and use in source and binary forms, with or
29 -* without modification, are permitted provided that the following
30 -* conditions are met: Redistributions of source code must retain the
31 -* above copyright notice, this list of conditions and the following
32 -* disclaimer. Redistributions in binary form must reproduce the above
33 -* copyright notice, this list of conditions and the following disclaimer
34 -* in the documentation and/or other materials provided with the
35 -* distribution.
36 -*
37 -* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
38 -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
39 -* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
40 -* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
41 -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
42 -* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
43 -* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
45 -* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
46 -* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
47 -* DAMAGE.
48 -*
49 -* @ingroup API
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$
55 -* @license http://www.opensource.org/licenses/bsd-license.php
56 -* @see 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 -*/
62 -define('SERVICES_JSON_SLICE', 1);
63 -
64 -/**
65 -* Marker constant for Services_JSON::decode(), used to flag stack state
66 -*/
67 -define('SERVICES_JSON_IN_STR', 2);
68 -
69 -/**
70 -* Marker constant for Services_JSON::decode(), used to flag stack state
71 -*/
72 -define('SERVICES_JSON_IN_ARR', 3);
73 -
74 -/**
75 -* Marker constant for Services_JSON::decode(), used to flag stack state
76 -*/
77 -define('SERVICES_JSON_IN_OBJ', 4);
78 -
79 -/**
80 -* Marker constant for Services_JSON::decode(), used to flag stack state
81 -*/
82 -define('SERVICES_JSON_IN_CMT', 5);
83 -
84 -/**
85 -* Behavior switch for Services_JSON::decode()
86 -*/
87 -define('SERVICES_JSON_LOOSE_TYPE', 16);
88 -
89 -/**
90 -* Behavior switch for Services_JSON::decode()
91 -*/
92 -define('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 - *
115 - * @ingroup API
116 - */
117 -class Services_JSON
118 -{
119 - /**
120 - * constructs a new JSON instance
121 - *
122 - * @param int $use object behavior flags; combine with boolean-OR
123 - *
124 - * possible values:
125 - * - SERVICES_JSON_LOOSE_TYPE: loose typing.
126 - * "{...}" syntax creates associative arrays
127 - * instead of objects in decode().
128 - * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
129 - * Values which can't be encoded (e.g. resources)
130 - * appear as NULL instead of throwing errors.
131 - * By default, a deeply-nested resource will
132 - * bubble up with an error, so all return values
133 - * from encode() should be checked with isError()
134 - */
135 - function Services_JSON($use = 0)
136 - {
137 - $this->use = $use;
138 - }
139 -
140 - /**
141 - * convert a string from one UTF-16 char to one UTF-8 char
142 - *
143 - * Normally should be handled by mb_convert_encoding, but
144 - * provides a slower PHP-only method for installations
145 - * that lack the multibye string extension.
146 - *
147 - * @param string $utf16 UTF-16 character
148 - * @return string UTF-8 character
149 - * @access private
150 - */
151 - function utf162utf8($utf16)
152 - {
153 - // oh please oh please oh please oh please oh please
154 - if(function_exists('mb_convert_encoding')) {
155 - return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
156 - }
157 -
158 - $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
159 -
160 - switch(true) {
161 - case ((0x7F & $bytes) == $bytes):
162 - // this case should never be reached, because we are in ASCII range
163 - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
164 - return chr(0x7F & $bytes);
165 -
166 - case (0x07FF & $bytes) == $bytes:
167 - // return a 2-byte UTF-8 character
168 - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
169 - return chr(0xC0 | (($bytes >> 6) & 0x1F))
170 - . chr(0x80 | ($bytes & 0x3F));
171 -
172 - case (0xFC00 & $bytes) == 0xD800 && strlen($utf16) >= 4 && (0xFC & ord($utf16{2})) == 0xDC:
173 - // return a 4-byte UTF-8 character
174 - $char = ((($bytes & 0x03FF) << 10)
175 - | ((ord($utf16{2}) & 0x03) << 8)
176 - | ord($utf16{3}));
177 - $char += 0x10000;
178 - return chr(0xF0 | (($char >> 18) & 0x07))
179 - . chr(0x80 | (($char >> 12) & 0x3F))
180 - . chr(0x80 | (($char >> 6) & 0x3F))
181 - . chr(0x80 | ($char & 0x3F));
182 -
183 - case (0xFFFF & $bytes) == $bytes:
184 - // return a 3-byte UTF-8 character
185 - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
186 - return chr(0xE0 | (($bytes >> 12) & 0x0F))
187 - . chr(0x80 | (($bytes >> 6) & 0x3F))
188 - . chr(0x80 | ($bytes & 0x3F));
189 - }
190 -
191 - // ignoring UTF-32 for now, sorry
192 - return '';
193 - }
194 -
195 - /**
196 - * convert a string from one UTF-8 char to one UTF-16 char
197 - *
198 - * Normally should be handled by mb_convert_encoding, but
199 - * provides a slower PHP-only method for installations
200 - * that lack the multibye string extension.
201 - *
202 - * @param string $utf8 UTF-8 character
203 - * @return string UTF-16 character
204 - * @access private
205 - */
206 - function utf82utf16($utf8)
207 - {
208 - // oh please oh please oh please oh please oh please
209 - if(function_exists('mb_convert_encoding')) {
210 - return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
211 - }
212 -
213 - switch(strlen($utf8)) {
214 - case 1:
215 - // this case should never be reached, because we are in ASCII range
216 - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
217 - return $utf8;
218 -
219 - case 2:
220 - // return a UTF-16 character from a 2-byte UTF-8 char
221 - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
222 - return chr(0x07 & (ord($utf8{0}) >> 2))
223 - . chr((0xC0 & (ord($utf8{0}) << 6))
224 - | (0x3F & ord($utf8{1})));
225 -
226 - case 3:
227 - // return a UTF-16 character from a 3-byte UTF-8 char
228 - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
229 - return chr((0xF0 & (ord($utf8{0}) << 4))
230 - | (0x0F & (ord($utf8{1}) >> 2)))
231 - . chr((0xC0 & (ord($utf8{1}) << 6))
232 - | (0x7F & ord($utf8{2})));
233 -
234 - case 4:
235 - // return a UTF-16 surrogate pair from a 4-byte UTF-8 char
236 - if(ord($utf8{0}) > 0xF4) return ''; # invalid
237 - $char = ((0x1C0000 & (ord($utf8{0}) << 18))
238 - | (0x03F000 & (ord($utf8{1}) << 12))
239 - | (0x000FC0 & (ord($utf8{2}) << 6))
240 - | (0x00003F & ord($utf8{3})));
241 - if($char > 0x10FFFF) return ''; # invalid
242 - $char -= 0x10000;
243 - return chr(0xD8 | (($char >> 18) & 0x03))
244 - . chr(($char >> 10) & 0xFF)
245 - . chr(0xDC | (($char >> 8) & 0x03))
246 - . chr($char & 0xFF);
247 - }
248 -
249 - // ignoring UTF-32 for now, sorry
250 - return '';
251 - }
252 -
253 - /**
254 - * encodes an arbitrary variable into JSON format
255 - *
256 - * @param mixed $var any number, boolean, string, array, or object to be encoded.
257 - * see argument 1 to Services_JSON() above for array-parsing behavior.
258 - * if var is a strng, note that encode() always expects it
259 - * to be in ASCII or UTF-8 format!
260 - * @param bool $pretty pretty-print output with indents and newlines
261 - *
262 - * @return mixed JSON string representation of input var or an error if a problem occurs
263 - * @access public
264 - */
265 - function encode($var, $pretty=false)
266 - {
267 - $this->indent = 0;
268 - $this->pretty = $pretty;
269 - $this->nameValSeparator = $pretty ? ': ' : ':';
270 - return $this->encode2($var);
271 - }
272 -
273 - /**
274 - * encodes an arbitrary variable into JSON format
275 - *
276 - * @param mixed $var any number, boolean, string, array, or object to be encoded.
277 - * see argument 1 to Services_JSON() above for array-parsing behavior.
278 - * if var is a strng, note that encode() always expects it
279 - * to be in ASCII or UTF-8 format!
280 - *
281 - * @return mixed JSON string representation of input var or an error if a problem occurs
282 - * @access private
283 - */
284 - function encode2($var)
285 - {
286 - if ($this->pretty) {
287 - $close = "\n" . str_repeat("\t", $this->indent);
288 - $open = $close . "\t";
289 - $mid = ',' . $open;
290 - }
291 - else {
292 - $open = $close = '';
293 - $mid = ',';
294 - }
295 -
296 - switch (gettype($var)) {
297 - case 'boolean':
298 - return $var ? 'true' : 'false';
299 -
300 - case 'NULL':
301 - return 'null';
302 -
303 - case 'integer':
304 - return (int) $var;
305 -
306 - case 'double':
307 - case 'float':
308 - return (float) $var;
309 -
310 - case 'string':
311 - // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
312 - $ascii = '';
313 - $strlen_var = strlen($var);
314 -
315 - /*
316 - * Iterate over every character in the string,
317 - * escaping with a slash or encoding to UTF-8 where necessary
318 - */
319 - for ($c = 0; $c < $strlen_var; ++$c) {
320 -
321 - $ord_var_c = ord($var{$c});
322 -
323 - switch (true) {
324 - case $ord_var_c == 0x08:
325 - $ascii .= '\b';
326 - break;
327 - case $ord_var_c == 0x09:
328 - $ascii .= '\t';
329 - break;
330 - case $ord_var_c == 0x0A:
331 - $ascii .= '\n';
332 - break;
333 - case $ord_var_c == 0x0C:
334 - $ascii .= '\f';
335 - break;
336 - case $ord_var_c == 0x0D:
337 - $ascii .= '\r';
338 - break;
339 -
340 - case $ord_var_c == 0x22:
341 - case $ord_var_c == 0x2F:
342 - case $ord_var_c == 0x5C:
343 - // double quote, slash, slosh
344 - $ascii .= '\\'.$var{$c};
345 - break;
346 -
347 - case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
348 - // characters U-00000000 - U-0000007F (same as ASCII)
349 - $ascii .= $var{$c};
350 - break;
351 -
352 - case (($ord_var_c & 0xE0) == 0xC0):
353 - // characters U-00000080 - U-000007FF, mask 110XXXXX
354 - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
355 - $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
356 - $c += 1;
357 - $utf16 = $this->utf82utf16($char);
358 - $ascii .= sprintf('\u%04s', bin2hex($utf16));
359 - break;
360 -
361 - case (($ord_var_c & 0xF0) == 0xE0):
362 - // characters U-00000800 - U-0000FFFF, mask 1110XXXX
363 - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
364 - $char = pack('C*', $ord_var_c,
365 - ord($var{$c + 1}),
366 - ord($var{$c + 2}));
367 - $c += 2;
368 - $utf16 = $this->utf82utf16($char);
369 - $ascii .= sprintf('\u%04s', bin2hex($utf16));
370 - break;
371 -
372 - case (($ord_var_c & 0xF8) == 0xF0):
373 - // characters U-00010000 - U-001FFFFF, mask 11110XXX
374 - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
375 - // These will always return a surrogate pair
376 - $char = pack('C*', $ord_var_c,
377 - ord($var{$c + 1}),
378 - ord($var{$c + 2}),
379 - ord($var{$c + 3}));
380 - $c += 3;
381 - $utf16 = $this->utf82utf16($char);
382 - if($utf16 == '') {
383 - $ascii .= '\ufffd';
384 - } else {
385 - $utf16 = str_split($utf16, 2);
386 - $ascii .= sprintf('\u%04s\u%04s', bin2hex($utf16[0]), bin2hex($utf16[1]));
387 - }
388 - break;
389 - }
390 - }
391 -
392 - return '"'.$ascii.'"';
393 -
394 - case 'array':
395 - /*
396 - * As per JSON spec if any array key is not an integer
397 - * we must treat the the whole array as an object. We
398 - * also try to catch a sparsely populated associative
399 - * array with numeric keys here because some JS engines
400 - * will create an array with empty indexes up to
401 - * max_index which can cause memory issues and because
402 - * the keys, which may be relevant, will be remapped
403 - * otherwise.
404 - *
405 - * As per the ECMA and JSON specification an object may
406 - * have any string as a property. Unfortunately due to
407 - * a hole in the ECMA specification if the key is a
408 - * ECMA reserved word or starts with a digit the
409 - * parameter is only accessible using ECMAScript's
410 - * bracket notation.
411 - */
412 -
413 - // treat as a JSON object
414 - if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
415 - $this->indent++;
416 - $properties = array_map(array($this, 'name_value'),
417 - array_keys($var),
418 - array_values($var));
419 - $this->indent--;
420 -
421 - foreach($properties as $property) {
422 - if(Services_JSON::isError($property)) {
423 - return $property;
424 - }
425 - }
426 -
427 - return '{' . $open . join($mid, $properties) . $close . '}';
428 - }
429 -
430 - // treat it like a regular array
431 - $this->indent++;
432 - $elements = array_map(array($this, 'encode2'), $var);
433 - $this->indent--;
434 -
435 - foreach($elements as $element) {
436 - if(Services_JSON::isError($element)) {
437 - return $element;
438 - }
439 - }
440 -
441 - return '[' . $open . join($mid, $elements) . $close . ']';
442 -
443 - case 'object':
444 - $vars = get_object_vars($var);
445 -
446 - $this->indent++;
447 - $properties = array_map(array($this, 'name_value'),
448 - array_keys($vars),
449 - array_values($vars));
450 - $this->indent--;
451 -
452 - foreach($properties as $property) {
453 - if(Services_JSON::isError($property)) {
454 - return $property;
455 - }
456 - }
457 -
458 - return '{' . $open . join($mid, $properties) . $close . '}';
459 -
460 - default:
461 - return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
462 - ? 'null'
463 - : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
464 - }
465 - }
466 -
467 - /**
468 - * array-walking function for use in generating JSON-formatted name-value pairs
469 - *
470 - * @param string $name name of key to use
471 - * @param mixed $value reference to an array element to be encoded
472 - *
473 - * @return string JSON-formatted name-value pair, like '"name":value'
474 - * @access private
475 - */
476 - function name_value($name, $value)
477 - {
478 - $encoded_value = $this->encode2($value);
479 -
480 - if(Services_JSON::isError($encoded_value)) {
481 - return $encoded_value;
482 - }
483 -
484 - return $this->encode2(strval($name)) . $this->nameValSeparator . $encoded_value;
485 - }
486 -
487 - /**
488 - * reduce a string by removing leading and trailing comments and whitespace
489 - *
490 - * @param $str string string value to strip of comments and whitespace
491 - *
492 - * @return string string value stripped of comments and whitespace
493 - * @access private
494 - */
495 - function reduce_string($str)
496 - {
497 - $str = preg_replace(array(
498 -
499 - // eliminate single line comments in '// ...' form
500 - '#^\s*//(.+)$#m',
501 -
502 - // eliminate multi-line comments in '/* ... */' form, at start of string
503 - '#^\s*/\*(.+)\*/#Us',
504 -
505 - // eliminate multi-line comments in '/* ... */' form, at end of string
506 - '#/\*(.+)\*/\s*$#Us'
507 -
508 - ), '', $str);
509 -
510 - // eliminate extraneous space
511 - return trim($str);
512 - }
513 -
514 - /**
515 - * decodes a JSON string into appropriate variable
516 - *
517 - * @param string $str JSON-formatted string
518 - *
519 - * @return mixed number, boolean, string, array, or object
520 - * corresponding to given JSON input string.
521 - * See argument 1 to Services_JSON() above for object-output behavior.
522 - * Note that decode() always returns strings
523 - * in ASCII or UTF-8 format!
524 - * @access public
525 - */
526 - function decode($str)
527 - {
528 - $str = $this->reduce_string($str);
529 -
530 - switch (strtolower($str)) {
531 - case 'true':
532 - return true;
533 -
534 - case 'false':
535 - return false;
536 -
537 - case 'null':
538 - return null;
539 -
540 - default:
541 - $m = array();
542 -
543 - if (is_numeric($str)) {
544 - // Lookie-loo, it's a number
545 -
546 - // This would work on its own, but I'm trying to be
547 - // good about returning integers where appropriate:
548 - // return (float)$str;
549 -
550 - // Return float or int, as appropriate
551 - return ((float)$str == (integer)$str)
552 - ? (integer)$str
553 - : (float)$str;
554 -
555 - } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
556 - // STRINGS RETURNED IN UTF-8 FORMAT
557 - $delim = substr($str, 0, 1);
558 - $chrs = substr($str, 1, -1);
559 - $utf8 = '';
560 - $strlen_chrs = strlen($chrs);
561 -
562 - for ($c = 0; $c < $strlen_chrs; ++$c) {
563 -
564 - $substr_chrs_c_2 = substr($chrs, $c, 2);
565 - $ord_chrs_c = ord($chrs{$c});
566 -
567 - switch (true) {
568 - case $substr_chrs_c_2 == '\b':
569 - $utf8 .= chr(0x08);
570 - ++$c;
571 - break;
572 - case $substr_chrs_c_2 == '\t':
573 - $utf8 .= chr(0x09);
574 - ++$c;
575 - break;
576 - case $substr_chrs_c_2 == '\n':
577 - $utf8 .= chr(0x0A);
578 - ++$c;
579 - break;
580 - case $substr_chrs_c_2 == '\f':
581 - $utf8 .= chr(0x0C);
582 - ++$c;
583 - break;
584 - case $substr_chrs_c_2 == '\r':
585 - $utf8 .= chr(0x0D);
586 - ++$c;
587 - break;
588 -
589 - case $substr_chrs_c_2 == '\\"':
590 - case $substr_chrs_c_2 == '\\\'':
591 - case $substr_chrs_c_2 == '\\\\':
592 - case $substr_chrs_c_2 == '\\/':
593 - if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
594 - ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
595 - $utf8 .= $chrs{++$c};
596 - }
597 - break;
598 -
599 - case preg_match('/\\\uD[89AB][0-9A-F]{2}\\\uD[C-F][0-9A-F]{2}/i', substr($chrs, $c, 12)):
600 - // escaped unicode surrogate pair
601 - $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
602 - . chr(hexdec(substr($chrs, ($c + 4), 2)))
603 - . chr(hexdec(substr($chrs, ($c + 8), 2)))
604 - . chr(hexdec(substr($chrs, ($c + 10), 2)));
605 - $utf8 .= $this->utf162utf8($utf16);
606 - $c += 11;
607 - break;
608 -
609 - case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
610 - // single, escaped unicode character
611 - $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
612 - . chr(hexdec(substr($chrs, ($c + 4), 2)));
613 - $utf8 .= $this->utf162utf8($utf16);
614 - $c += 5;
615 - break;
616 -
617 - case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
618 - $utf8 .= $chrs{$c};
619 - break;
620 -
621 - case ($ord_chrs_c & 0xE0) == 0xC0:
622 - // characters U-00000080 - U-000007FF, mask 110XXXXX
623 - //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
624 - $utf8 .= substr($chrs, $c, 2);
625 - ++$c;
626 - break;
627 -
628 - case ($ord_chrs_c & 0xF0) == 0xE0:
629 - // characters U-00000800 - U-0000FFFF, mask 1110XXXX
630 - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
631 - $utf8 .= substr($chrs, $c, 3);
632 - $c += 2;
633 - break;
634 -
635 - case ($ord_chrs_c & 0xF8) == 0xF0:
636 - // characters U-00010000 - U-001FFFFF, mask 11110XXX
637 - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
638 - $utf8 .= substr($chrs, $c, 4);
639 - $c += 3;
640 - break;
641 -
642 - case ($ord_chrs_c & 0xFC) == 0xF8:
643 - // characters U-00200000 - U-03FFFFFF, mask 111110XX
644 - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
645 - $utf8 .= substr($chrs, $c, 5);
646 - $c += 4;
647 - break;
648 -
649 - case ($ord_chrs_c & 0xFE) == 0xFC:
650 - // characters U-04000000 - U-7FFFFFFF, mask 1111110X
651 - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
652 - $utf8 .= substr($chrs, $c, 6);
653 - $c += 5;
654 - break;
655 -
656 - }
657 -
658 - }
659 -
660 - return $utf8;
661 -
662 - } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
663 - // array, or object notation
664 -
665 - if ($str{0} == '[') {
666 - $stk = array(SERVICES_JSON_IN_ARR);
667 - $arr = array();
668 - } else {
669 - if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
670 - $stk = array(SERVICES_JSON_IN_OBJ);
671 - $obj = array();
672 - } else {
673 - $stk = array(SERVICES_JSON_IN_OBJ);
674 - $obj = new stdClass();
675 - }
676 - }
677 -
678 - array_push($stk, array( 'what' => SERVICES_JSON_SLICE,
679 - 'where' => 0,
680 - 'delim' => false));
681 -
682 - $chrs = substr($str, 1, -1);
683 - $chrs = $this->reduce_string($chrs);
684 -
685 - if ($chrs == '') {
686 - if (reset($stk) == SERVICES_JSON_IN_ARR) {
687 - return $arr;
688 -
689 - } else {
690 - return $obj;
691 -
692 - }
693 - }
694 -
695 - //print("\nparsing {$chrs}\n");
696 -
697 - $strlen_chrs = strlen($chrs);
698 -
699 - for ($c = 0; $c <= $strlen_chrs; ++$c) {
700 -
701 - $top = end($stk);
702 - $substr_chrs_c_2 = substr($chrs, $c, 2);
703 -
704 - if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
705 - // found a comma that is not inside a string, array, etc.,
706 - // OR we've reached the end of the character list
707 - $slice = substr($chrs, $top['where'], ($c - $top['where']));
708 - array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
709 - //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
710 -
711 - if (reset($stk) == SERVICES_JSON_IN_ARR) {
712 - // we are in an array, so just push an element onto the stack
713 - array_push($arr, $this->decode($slice));
714 -
715 - } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
716 - // we are in an object, so figure
717 - // out the property name and set an
718 - // element in an associative array,
719 - // for now
720 - $parts = array();
721 -
722 - if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
723 - // "name":value pair
724 - $key = $this->decode($parts[1]);
725 - $val = $this->decode($parts[2]);
726 -
727 - if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
728 - $obj[$key] = $val;
729 - } else {
730 - $obj->$key = $val;
731 - }
732 - } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
733 - // name:value pair, where name is unquoted
734 - $key = $parts[1];
735 - $val = $this->decode($parts[2]);
736 -
737 - if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
738 - $obj[$key] = $val;
739 - } else {
740 - $obj->$key = $val;
741 - }
742 - }
743 -
744 - }
745 -
746 - } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
747 - // found a quote, and we are not inside a string
748 - array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
749 - //print("Found start of string at {$c}\n");
750 -
751 - } elseif (($chrs{$c} == $top['delim']) &&
752 - ($top['what'] == SERVICES_JSON_IN_STR) &&
753 - (($chrs{$c - 1} != '\\') ||
754 - ($chrs{$c - 1} == '\\' && $chrs{$c - 2} == '\\'))) {
755 - // found a quote, we're in a string, and it's not escaped
756 - array_pop($stk);
757 - //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
758 -
759 - } elseif (($chrs{$c} == '[') &&
760 - in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
761 - // found a left-bracket, and we are in an array, object, or slice
762 - array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
763 - //print("Found start of array at {$c}\n");
764 -
765 - } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
766 - // found a right-bracket, and we're in an array
767 - array_pop($stk);
768 - //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
769 -
770 - } elseif (($chrs{$c} == '{') &&
771 - in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
772 - // found a left-brace, and we are in an array, object, or slice
773 - array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
774 - //print("Found start of object at {$c}\n");
775 -
776 - } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
777 - // found a right-brace, and we're in an object
778 - array_pop($stk);
779 - //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
780 -
781 - } elseif (($substr_chrs_c_2 == '/*') &&
782 - in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
783 - // found a comment start, and we are in an array, object, or slice
784 - array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
785 - $c++;
786 - //print("Found start of comment at {$c}\n");
787 -
788 - } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
789 - // found a comment end, and we're in one now
790 - array_pop($stk);
791 - $c++;
792 -
793 - for ($i = $top['where']; $i <= $c; ++$i)
794 - $chrs = substr_replace($chrs, ' ', $i, 1);
795 -
796 - //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
797 -
798 - }
799 -
800 - }
801 -
802 - if (reset($stk) == SERVICES_JSON_IN_ARR) {
803 - return $arr;
804 -
805 - } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
806 - return $obj;
807 -
808 - }
809 -
810 - }
811 - }
812 - }
813 -
814 - /**
815 - * @todo Ultimately, this should just call PEAR::isError()
816 - */
817 - function isError($data, $code = null)
818 - {
819 - if (class_exists('pear')) {
820 - //avoid some strict warnings on PEAR isError check (looks like http://pear.php.net/bugs/bug.php?id=9950 has been around for some time)
821 - return @PEAR::isError($data, $code);
822 - } elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
823 - is_subclass_of($data, 'services_json_error'))) {
824 - return true;
825 - }
826 -
827 - return false;
828 - }
829 -}
830 -
831 -
832 -// Hide the PEAR_Error variant from Doxygen
833 -/// @cond
834 -if (class_exists('PEAR_Error')) {
835 -
836 - /**
837 - * @ingroup API
838 - */
839 - class Services_JSON_Error extends PEAR_Error
840 - {
841 - function Services_JSON_Error($message = 'unknown error', $code = null,
842 - $mode = null, $options = null, $userinfo = null)
843 - {
844 - parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
845 - }
846 - }
847 -
848 -} else {
849 -/// @endcond
850 -
851 - /**
852 - * @todo Ultimately, this class shall be descended from PEAR_Error
853 - * @ingroup API
854 - */
855 - class Services_JSON_Error
856 - {
857 - function Services_JSON_Error($message = 'unknown error', $code = null,
858 - $mode = null, $options = null, $userinfo = null)
859 - {
860 -
861 - }
862 - }
863 -}
Index: trunk/phase3/includes/AutoLoader.php
@@ -318,11 +318,15 @@
319319 'ApiUserrights' => 'includes/api/ApiUserrights.php',
320320 'ApiUpload' => 'includes/api/ApiUpload.php',
321321 'ApiWatch' => 'includes/api/ApiWatch.php',
322 - 'Services_JSON' => 'includes/api/ApiFormatJson_json.php',
323 - 'Services_JSON_Error' => 'includes/api/ApiFormatJson_json.php',
 322+
324323 'Spyc' => 'includes/api/ApiFormatYaml_spyc.php',
325324 'UsageException' => 'includes/api/ApiMain.php',
326325
 326+ # includes/json
 327+ 'Services_JSON' => 'includes/json/Services_JSON.php',
 328+ 'Services_JSON_Error' => 'includes/json/Services_JSON.php',
 329+ 'FormatJson' => 'includes/json/FormatJson.php',
 330+
327331 # includes/db
328332 'Blob' => 'includes/db/Database.php',
329333 'ChronologyProtector' => 'includes/db/LBFactory.php',
Index: trunk/phase3/includes/HttpFunctions.php
@@ -206,7 +206,7 @@
207207 $sd =& $_SESSION['wsDownload'][$upload_session_key];
208208 // if error update status:
209209 if( !$status->isOK() ) {
210 - $sd['apiUploadResult'] = ApiFormatJson::getJsonEncode(
 210+ $sd['apiUploadResult'] = FormatJson::encode(
211211 array( 'error' => $status->getWikiText() )
212212 );
213213 }
Index: trunk/phase3/js2/mwEmbed/php/maintenance/mergeJavascriptMsg.php
@@ -112,14 +112,14 @@
113113 }
114114 // merge the jsLanguage array back in and wrap the output
115115 if ( $mergeToJS && $doReplaceFlag ) {
116 - $json = json_encode( $jsMsgAry );
 116+ $json = FormatJson::encode( $jsMsgAry );
117117 $json_txt = jsonReadable( $json );
118118 // escape $1 for preg replace:
119119 $json_txt = str_replace( '$', '\$', $json_txt );
120120 // print "json:\n$json_txt \n";
121121 $str = preg_replace ( '/loadGM\s*\(\s*{(.*)}\s*\)\s*/siU',
122 - "loadGM(" . $json_txt . ")",
123 - $jsFileText );
 122+ "loadGM(" . $json_txt . ")",
 123+ $jsFileText );
124124
125125 // print substr($str, 0, 600);
126126
Index: trunk/phase3/js2/mwEmbed/php/languages/mwEmbed.i18n.php
@@ -34,7 +34,7 @@
3535 'mwe-set_in_out_points' => 'Set in-out points',
3636 'mwe-start_time' => 'Start time',
3737 'mwe-end_time' => 'End time',
38 - 'mwe-preview_inout' => 'Preview/play in-out points',
 38+ 'mwe-preview_inout' => 'Preview in-out points',
3939
4040 /*
4141 * js file: /libTimedText/mvTextInterface.js
Index: trunk/phase3/js2/mwEmbed/skins/ctrlBuilder.js
@@ -331,4 +331,4 @@
332332 }
333333 }
334334 }
335 -}
\ No newline at end of file
 335+};

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r56116* (bug 20336) changed json_decode json_encode to static class in global funct...dale22:26, 9 September 2009

Comments

#Comment by Brion VIBBER (talk | contribs)   19:22, 10 September 2009

Showstopper decoding bug in r56116 still here.

#Comment by Siebrand (talk | contribs)   19:08, 22 September 2009

PHP Fatal error: Class 'FormatJson' not found in phase3\js2\mwEmbed\php\maintenance\mergeJavascriptMsg.php on line 115

#Comment by Siebrand (talk | contribs)   19:24, 22 September 2009

Fixed by Michael in r56781. Thanks.

Status & tagging log