MediaWiki REL1_34
MWMessagePack.php
Go to the documentation of this file.
1<?php
38 public static $bigendian = null;
39
53 public static function pack( $value ) {
54 wfDeprecated( __METHOD__, '1.34' );
55 if ( self::$bigendian === null ) {
56 self::$bigendian = pack( 'S', 1 ) === pack( 'n', 1 );
57 }
58
59 switch ( gettype( $value ) ) {
60 case 'NULL':
61 return "\xC0";
62
63 case 'boolean':
64 return $value ? "\xC3" : "\xC2";
65
66 case 'double':
67 case 'float':
68 return self::$bigendian
69 ? "\xCB" . pack( 'd', $value )
70 : "\xCB" . strrev( pack( 'd', $value ) );
71
72 case 'string':
73 $length = strlen( $value );
74 if ( $length < 32 ) {
75 return pack( 'Ca*', 0xA0 | $length, $value );
76 } elseif ( $length <= 0xFFFF ) {
77 return pack( 'Cna*', 0xDA, $length, $value );
78 } elseif ( $length <= 0xFFFFFFFF ) {
79 return pack( 'CNa*', 0xDB, $length, $value );
80 }
81 throw new InvalidArgumentException( __METHOD__
82 . ": string too long (length: $length; max: 4294967295)" );
83
84 case 'integer':
85 if ( $value >= 0 ) {
86 if ( $value <= 0x7F ) {
87 // positive fixnum
88 return chr( $value );
89 }
90 if ( $value <= 0xFF ) {
91 // uint8
92 return pack( 'CC', 0xCC, $value );
93 }
94 if ( $value <= 0xFFFF ) {
95 // uint16
96 return pack( 'Cn', 0xCD, $value );
97 }
98 if ( $value <= 0xFFFFFFFF ) {
99 // uint32
100 return pack( 'CN', 0xCE, $value );
101 }
102 if ( $value <= 0xFFFFFFFFFFFFFFFF ) {
103 // uint64
104 $hi = ( $value & 0xFFFFFFFF00000000 ) >> 32;
105 $lo = $value & 0xFFFFFFFF;
106 return self::$bigendian
107 ? pack( 'CNN', 0xCF, $lo, $hi )
108 : pack( 'CNN', 0xCF, $hi, $lo );
109 }
110 } else {
111 if ( $value >= -32 ) {
112 // negative fixnum
113 return pack( 'c', $value );
114 }
115 if ( $value >= -0x80 ) {
116 // int8
117 return pack( 'Cc', 0xD0, $value );
118 }
119 if ( $value >= -0x8000 ) {
120 // int16
121 $p = pack( 's', $value );
122 return self::$bigendian
123 ? pack( 'Ca2', 0xD1, $p )
124 : pack( 'Ca2', 0xD1, strrev( $p ) );
125 }
126 if ( $value >= -0x80000000 ) {
127 // int32
128 $p = pack( 'l', $value );
129 return self::$bigendian
130 ? pack( 'Ca4', 0xD2, $p )
131 : pack( 'Ca4', 0xD2, strrev( $p ) );
132 }
133 if ( $value >= -0x8000000000000000 ) {
134 // int64
135 // pack() does not support 64-bit ints either so pack into two 32-bits
136 $p1 = pack( 'l', $value & 0xFFFFFFFF );
137 // @phan-suppress-next-line PhanTypeInvalidLeftOperandOfIntegerOp
138 $p2 = pack( 'l', ( $value >> 32 ) & 0xFFFFFFFF );
139 return self::$bigendian
140 ? pack( 'Ca4a4', 0xD3, $p1, $p2 )
141 : pack( 'Ca4a4', 0xD3, strrev( $p2 ), strrev( $p1 ) );
142 }
143 }
144 throw new InvalidArgumentException( __METHOD__ . ": invalid integer '$value'" );
145
146 case 'array':
147 $buffer = '';
148 $length = count( $value );
149 if ( $length > 0xFFFFFFFF ) {
150 throw new InvalidArgumentException( __METHOD__
151 . ": array too long (length: $length, max: 4294967295)" );
152 }
153
154 $index = 0;
155 foreach ( $value as $k => $v ) {
156 if ( $index !== $k || $index === $length ) {
157 break;
158 } else {
159 $index++;
160 }
161 }
162 $associative = $index !== $length;
163
164 if ( $associative ) {
165 if ( $length < 16 ) {
166 $buffer .= pack( 'C', 0x80 | $length );
167 } elseif ( $length <= 0xFFFF ) {
168 $buffer .= pack( 'Cn', 0xDE, $length );
169 } else {
170 $buffer .= pack( 'CN', 0xDF, $length );
171 }
172 foreach ( $value as $k => $v ) {
173 $buffer .= self::pack( $k );
174 $buffer .= self::pack( $v );
175 }
176 } else {
177 if ( $length < 16 ) {
178 $buffer .= pack( 'C', 0x90 | $length );
179 } elseif ( $length <= 0xFFFF ) {
180 $buffer .= pack( 'Cn', 0xDC, $length );
181 } else {
182 $buffer .= pack( 'CN', 0xDD, $length );
183 }
184 foreach ( $value as $v ) {
185 $buffer .= self::pack( $v );
186 }
187 }
188 return $buffer;
189
190 default:
191 throw new InvalidArgumentException( __METHOD__ . ': unsupported type ' . gettype( $value ) );
192 }
193 }
194}
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
static bool null $bigendian
Whether current system is bigendian.
static pack( $value)
Encode a value using MessagePack.