MediaWiki
REL1_23
|
00001 <?php 00035 class MWMessagePack { 00036 00038 public static $bigendian = null; 00039 00051 public static function pack( $value ) { 00052 if ( self::$bigendian === null ) { 00053 self::$bigendian = pack( 'S', 1 ) === pack( 'n', 1 ); 00054 } 00055 00056 switch ( gettype( $value ) ) { 00057 case 'NULL': 00058 return "\xC0"; 00059 00060 case 'boolean': 00061 return $value ? "\xC3" : "\xC2"; 00062 00063 case 'double': 00064 case 'float': 00065 return self::$bigendian 00066 ? "\xCB" . pack( 'd', $value ) 00067 : "\xCB" . strrev( pack( 'd', $value ) ); 00068 00069 case 'string': 00070 $length = strlen( $value ); 00071 if ( $length < 32 ) { 00072 return pack( 'Ca*', 0xA0 | $length, $value ); 00073 } elseif ( $length <= 0xFFFF ) { 00074 return pack( 'Cna*', 0xDA, $length, $value ); 00075 } elseif ( $length <= 0xFFFFFFFF ) { 00076 return pack( 'CNa*', 0xDB, $length, $value ); 00077 } 00078 throw new InvalidArgumentException( __METHOD__ . ": string too long (length: $length; max: 4294967295)" ); 00079 00080 case 'integer': 00081 if ( $value >= 0 ) { 00082 if ( $value <= 0x7F ) { 00083 // positive fixnum 00084 return chr( $value ); 00085 } 00086 if ( $value <= 0xFF ) { 00087 // uint8 00088 return pack( 'CC', 0xCC, $value ); 00089 } 00090 if ( $value <= 0xFFFF ) { 00091 // uint16 00092 return pack( 'Cn', 0xCD, $value ); 00093 } 00094 if ( $value <= 0xFFFFFFFF ) { 00095 // uint32 00096 return pack( 'CN', 0xCE, $value ); 00097 } 00098 if ( $value <= 0xFFFFFFFFFFFFFFFF ) { 00099 // uint64 00100 $hi = ( $value & 0xFFFFFFFF00000000 ) >> 32; 00101 $lo = $value & 0xFFFFFFFF; 00102 return self::$bigendian 00103 ? pack( 'CNN', 0xCF, $lo, $hi ) 00104 : pack( 'CNN', 0xCF, $hi, $lo ); 00105 } 00106 } else { 00107 if ( $value >= -32 ) { 00108 // negative fixnum 00109 return pack( 'c', $value ); 00110 } 00111 if ( $value >= -0x80 ) { 00112 // int8 00113 return pack( 'Cc', 0xD0, $value ); 00114 } 00115 if ( $value >= -0x8000 ) { 00116 // int16 00117 $p = pack( 's', $value ); 00118 return self::$bigendian 00119 ? pack( 'Ca2', 0xD1, $p ) 00120 : pack( 'Ca2', 0xD1, strrev( $p ) ); 00121 } 00122 if ( $value >= -0x80000000 ) { 00123 // int32 00124 $p = pack( 'l', $value ); 00125 return self::$bigendian 00126 ? pack( 'Ca4', 0xD2, $p ) 00127 : pack( 'Ca4', 0xD2, strrev( $p ) ); 00128 } 00129 if ( $value >= -0x8000000000000000 ) { 00130 // int64 00131 // pack() does not support 64-bit ints either so pack into two 32-bits 00132 $p1 = pack( 'l', $value & 0xFFFFFFFF ); 00133 $p2 = pack( 'l', ( $value >> 32 ) & 0xFFFFFFFF ); 00134 return self::$bigendian 00135 ? pack( 'Ca4a4', 0xD3, $p1, $p2 ) 00136 : pack( 'Ca4a4', 0xD3, strrev( $p2 ), strrev( $p1 ) ); 00137 } 00138 } 00139 throw new InvalidArgumentException( __METHOD__ . ": invalid integer '$value'" ); 00140 00141 case 'array': 00142 $buffer = ''; 00143 $length = count( $value ); 00144 if ( $length > 0xFFFFFFFF ) { 00145 throw new InvalidArgumentException( __METHOD__ . ": array too long (length: $length, max: 4294967295)" ); 00146 } 00147 00148 $index = 0; 00149 foreach ( $value as $k => $v ) { 00150 if ( $index !== $k || $index === $length ) { 00151 break; 00152 } else { 00153 $index++; 00154 } 00155 } 00156 $associative = $index !== $length; 00157 00158 if ( $associative ) { 00159 if ( $length < 16 ) { 00160 $buffer .= pack( 'C', 0x80 | $length ); 00161 } elseif ( $length <= 0xFFFF ) { 00162 $buffer .= pack( 'Cn', 0xDE, $length ); 00163 } else { 00164 $buffer .= pack( 'CN', 0xDF, $length ); 00165 } 00166 foreach ( $value as $k => $v ) { 00167 $buffer .= self::pack( $k ); 00168 $buffer .= self::pack( $v ); 00169 } 00170 } else { 00171 if ( $length < 16 ) { 00172 $buffer .= pack( 'C', 0x90 | $length ); 00173 } elseif ( $length <= 0xFFFF ) { 00174 $buffer .= pack( 'Cn', 0xDC, $length ); 00175 } else { 00176 $buffer .= pack( 'CN', 0xDD, $length ); 00177 } 00178 foreach ( $value as $v ) { 00179 $buffer .= self::pack( $v ); 00180 } 00181 } 00182 return $buffer; 00183 00184 default: 00185 throw new InvalidArgumentException( __METHOD__ . ': unsupported type ' . gettype( $value ) ); 00186 } 00187 } 00188 }