MediaWiki  master
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 }
static pack( $value)
Encode a value using MessagePack.
static bool null $bigendian
Whether current system is bigendian.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.