MediaWiki
REL1_24
|
00001 <?php 00035 class MWMessagePack { 00037 public static $bigendian = null; 00038 00050 public static function pack( $value ) { 00051 if ( self::$bigendian === null ) { 00052 self::$bigendian = pack( 'S', 1 ) === pack( 'n', 1 ); 00053 } 00054 00055 switch ( gettype( $value ) ) { 00056 case 'NULL': 00057 return "\xC0"; 00058 00059 case 'boolean': 00060 return $value ? "\xC3" : "\xC2"; 00061 00062 case 'double': 00063 case 'float': 00064 return self::$bigendian 00065 ? "\xCB" . pack( 'd', $value ) 00066 : "\xCB" . strrev( pack( 'd', $value ) ); 00067 00068 case 'string': 00069 $length = strlen( $value ); 00070 if ( $length < 32 ) { 00071 return pack( 'Ca*', 0xA0 | $length, $value ); 00072 } elseif ( $length <= 0xFFFF ) { 00073 return pack( 'Cna*', 0xDA, $length, $value ); 00074 } elseif ( $length <= 0xFFFFFFFF ) { 00075 return pack( 'CNa*', 0xDB, $length, $value ); 00076 } 00077 throw new InvalidArgumentException( __METHOD__ 00078 . ": 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__ 00146 . ": array too long (length: $length, max: 4294967295)" ); 00147 } 00148 00149 $index = 0; 00150 foreach ( $value as $k => $v ) { 00151 if ( $index !== $k || $index === $length ) { 00152 break; 00153 } else { 00154 $index++; 00155 } 00156 } 00157 $associative = $index !== $length; 00158 00159 if ( $associative ) { 00160 if ( $length < 16 ) { 00161 $buffer .= pack( 'C', 0x80 | $length ); 00162 } elseif ( $length <= 0xFFFF ) { 00163 $buffer .= pack( 'Cn', 0xDE, $length ); 00164 } else { 00165 $buffer .= pack( 'CN', 0xDF, $length ); 00166 } 00167 foreach ( $value as $k => $v ) { 00168 $buffer .= self::pack( $k ); 00169 $buffer .= self::pack( $v ); 00170 } 00171 } else { 00172 if ( $length < 16 ) { 00173 $buffer .= pack( 'C', 0x90 | $length ); 00174 } elseif ( $length <= 0xFFFF ) { 00175 $buffer .= pack( 'Cn', 0xDC, $length ); 00176 } else { 00177 $buffer .= pack( 'CN', 0xDD, $length ); 00178 } 00179 foreach ( $value as $v ) { 00180 $buffer .= self::pack( $v ); 00181 } 00182 } 00183 return $buffer; 00184 00185 default: 00186 throw new InvalidArgumentException( __METHOD__ . ': unsupported type ' . gettype( $value ) ); 00187 } 00188 } 00189 }