[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/libs/ -> MWMessagePack.php (source)

   1  <?php
   2  /**
   3   * MessagePack serializer
   4   *
   5   * MessagePack is a space-efficient binary data interchange format. This
   6   * class provides a pack() method that encodes native PHP values as MessagePack
   7   * binary strings. The implementation is derived from msgpack-php.
   8   *
   9   * Copyright (c) 2013 Ori Livneh <[email protected]>
  10   * Copyright (c) 2011 OnlineCity <https://github.com/onlinecity/msgpack-php>.
  11   *
  12   * Permission is hereby granted, free of charge, to any person obtaining a copy
  13   * of this software and associated documentation files (the "Software"), to
  14   * deal in the Software without restriction, including without limitation the
  15   * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  16   * sell copies of the Software, and to permit persons to whom the Software is
  17   * furnished to do so, subject to the following conditions:
  18   *
  19   * The above copyright notice and this permission notice shall be included in
  20   * all copies or substantial portions of the Software.
  21   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  26   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  27   * IN THE SOFTWARE.
  28   *
  29   * @see <http://msgpack.org/>
  30   * @see <http://wiki.msgpack.org/display/MSGPACK/Format+specification>
  31   *
  32   * @since 1.23
  33   * @file
  34   */
  35  class MWMessagePack {
  36      /** @var boolean|null Whether current system is bigendian. **/
  37      public static $bigendian = null;
  38  
  39      /**
  40       * Encode a value using MessagePack
  41       *
  42       * This method supports null, boolean, integer, float, string and array
  43       * (both indexed and associative) types. Object serialization is not
  44       * supported.
  45       *
  46       * @param mixed $value
  47       * @return string
  48       * @throws InvalidArgumentException if $value is an unsupported type or too long a string
  49       */
  50  	public static function pack( $value ) {
  51          if ( self::$bigendian === null ) {
  52              self::$bigendian = pack( 'S', 1 ) === pack( 'n', 1 );
  53          }
  54  
  55          switch ( gettype( $value ) ) {
  56          case 'NULL':
  57              return "\xC0";
  58  
  59          case 'boolean':
  60              return $value ? "\xC3" : "\xC2";
  61  
  62          case 'double':
  63          case 'float':
  64              return self::$bigendian
  65                  ? "\xCB" . pack( 'd', $value )
  66                  : "\xCB" . strrev( pack( 'd', $value ) );
  67  
  68          case 'string':
  69              $length = strlen( $value );
  70              if ( $length < 32 ) {
  71                  return pack( 'Ca*', 0xA0 | $length, $value );
  72              } elseif ( $length <= 0xFFFF ) {
  73                  return pack( 'Cna*', 0xDA, $length, $value );
  74              } elseif ( $length <= 0xFFFFFFFF ) {
  75                  return pack( 'CNa*', 0xDB, $length, $value );
  76              }
  77              throw new InvalidArgumentException( __METHOD__
  78                  . ": string too long (length: $length; max: 4294967295)" );
  79  
  80          case 'integer':
  81              if ( $value >= 0 ) {
  82                  if ( $value <= 0x7F ) {
  83                      // positive fixnum
  84                      return chr( $value );
  85                  }
  86                  if ( $value <= 0xFF ) {
  87                      // uint8
  88                      return pack( 'CC', 0xCC, $value );
  89                  }
  90                  if ( $value <= 0xFFFF ) {
  91                      // uint16
  92                      return pack( 'Cn', 0xCD, $value );
  93                  }
  94                  if ( $value <= 0xFFFFFFFF ) {
  95                      // uint32
  96                      return pack( 'CN', 0xCE, $value );
  97                  }
  98                  if ( $value <= 0xFFFFFFFFFFFFFFFF ) {
  99                      // uint64
 100                      $hi = ( $value & 0xFFFFFFFF00000000 ) >> 32;
 101                      $lo = $value & 0xFFFFFFFF;
 102                      return self::$bigendian
 103                          ? pack( 'CNN', 0xCF, $lo, $hi )
 104                          : pack( 'CNN', 0xCF, $hi, $lo );
 105                  }
 106              } else {
 107                  if ( $value >= -32 ) {
 108                      // negative fixnum
 109                      return pack( 'c', $value );
 110                  }
 111                  if ( $value >= -0x80 ) {
 112                      // int8
 113                      return pack( 'Cc', 0xD0, $value );
 114                  }
 115                  if ( $value >= -0x8000 ) {
 116                      // int16
 117                      $p = pack( 's', $value );
 118                      return self::$bigendian
 119                          ? pack( 'Ca2', 0xD1, $p )
 120                          : pack( 'Ca2', 0xD1, strrev( $p ) );
 121                  }
 122                  if ( $value >= -0x80000000 ) {
 123                      // int32
 124                      $p = pack( 'l', $value );
 125                      return self::$bigendian
 126                          ? pack( 'Ca4', 0xD2, $p )
 127                          : pack( 'Ca4', 0xD2, strrev( $p ) );
 128                  }
 129                  if ( $value >= -0x8000000000000000 ) {
 130                      // int64
 131                      // pack() does not support 64-bit ints either so pack into two 32-bits
 132                      $p1 = pack( 'l', $value & 0xFFFFFFFF );
 133                      $p2 = pack( 'l', ( $value >> 32 ) & 0xFFFFFFFF );
 134                      return self::$bigendian
 135                          ? pack( 'Ca4a4', 0xD3, $p1, $p2 )
 136                          : pack( 'Ca4a4', 0xD3, strrev( $p2 ), strrev( $p1 ) );
 137                  }
 138              }
 139              throw new InvalidArgumentException( __METHOD__ . ": invalid integer '$value'" );
 140  
 141          case 'array':
 142              $buffer = '';
 143              $length = count( $value );
 144              if ( $length > 0xFFFFFFFF ) {
 145                  throw new InvalidArgumentException( __METHOD__
 146                      . ": array too long (length: $length, max: 4294967295)" );
 147              }
 148  
 149              $index = 0;
 150              foreach ( $value as $k => $v ) {
 151                  if ( $index !== $k || $index === $length ) {
 152                      break;
 153                  } else {
 154                      $index++;
 155                  }
 156              }
 157              $associative = $index !== $length;
 158  
 159              if ( $associative ) {
 160                  if ( $length < 16 ) {
 161                      $buffer .= pack( 'C', 0x80 | $length );
 162                  } elseif ( $length <= 0xFFFF ) {
 163                      $buffer .= pack( 'Cn', 0xDE, $length );
 164                  } else {
 165                      $buffer .= pack( 'CN', 0xDF, $length );
 166                  }
 167                  foreach ( $value as $k => $v ) {
 168                      $buffer .= self::pack( $k );
 169                      $buffer .= self::pack( $v );
 170                  }
 171              } else {
 172                  if ( $length < 16 ) {
 173                      $buffer .= pack( 'C', 0x90 | $length );
 174                  } elseif ( $length <= 0xFFFF ) {
 175                      $buffer .= pack( 'Cn', 0xDC, $length );
 176                  } else {
 177                      $buffer .= pack( 'CN', 0xDD, $length );
 178                  }
 179                  foreach ( $value as $v ) {
 180                      $buffer .= self::pack( $v );
 181                  }
 182              }
 183              return $buffer;
 184  
 185          default:
 186              throw new InvalidArgumentException( __METHOD__ . ': unsupported type ' . gettype( $value ) );
 187          }
 188      }
 189  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1