MediaWiki REL1_31
MWMessagePack.php
Go to the documentation of this file.
1<?php
37 public static $bigendian = null;
38
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}
static bool null $bigendian
Whether current system is bigendian.
static pack( $value)
Encode a value using MessagePack.
$buffer