MWMessagePack.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <?php
  2. /**
  3. * MessagePack serializer
  4. *
  5. * MessagePack is a space-efficient binary data interchange format. This
  6. * class provides a pack() method that encodes native PHP values as MessagePack
  7. * binary strings. The implementation is derived from msgpack-php.
  8. *
  9. * Copyright (c) 2013 Ori Livneh <ori@wikimedia.org>
  10. * Copyright (c) 2011 OnlineCity <https://github.com/onlinecity/msgpack-php>.
  11. *
  12. * Permission is hereby granted, free of charge, to any person obtaining a copy
  13. * of this software and associated documentation files (the "Software"), to
  14. * deal in the Software without restriction, including without limitation the
  15. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  16. * sell copies of the Software, and to permit persons to whom the Software is
  17. * furnished to do so, subject to the following conditions:
  18. *
  19. * The above copyright notice and this permission notice shall be included in
  20. * all copies or substantial portions of the Software.
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  26. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  27. * IN THE SOFTWARE.
  28. *
  29. * @see <http://msgpack.org/>
  30. * @see <http://wiki.msgpack.org/display/MSGPACK/Format+specification>
  31. *
  32. * @since 1.23
  33. * @file
  34. * @deprecated since 1.34, no longer used
  35. */
  36. class MWMessagePack {
  37. /** @var bool|null Whether current system is bigendian. */
  38. public static $bigendian = null;
  39. /**
  40. * Encode a value using MessagePack
  41. *
  42. * This method supports null, boolean, integer, float, string and array
  43. * (both indexed and associative) types. Object serialization is not
  44. * supported.
  45. *
  46. * @deprecated since 1.34, no longer used
  47. *
  48. * @param mixed $value
  49. * @return string
  50. * @throws InvalidArgumentException if $value is an unsupported type or too long a string
  51. */
  52. public static function pack( $value ) {
  53. wfDeprecated( __METHOD__, '1.34' );
  54. if ( self::$bigendian === null ) {
  55. self::$bigendian = pack( 'S', 1 ) === pack( 'n', 1 );
  56. }
  57. switch ( gettype( $value ) ) {
  58. case 'NULL':
  59. return "\xC0";
  60. case 'boolean':
  61. return $value ? "\xC3" : "\xC2";
  62. case 'double':
  63. case 'float':
  64. return self::$bigendian
  65. ? "\xCB" . pack( 'd', $value )
  66. : "\xCB" . strrev( pack( 'd', $value ) );
  67. case 'string':
  68. $length = strlen( $value );
  69. if ( $length < 32 ) {
  70. return pack( 'Ca*', 0xA0 | $length, $value );
  71. } elseif ( $length <= 0xFFFF ) {
  72. return pack( 'Cna*', 0xDA, $length, $value );
  73. } elseif ( $length <= 0xFFFFFFFF ) {
  74. return pack( 'CNa*', 0xDB, $length, $value );
  75. }
  76. throw new InvalidArgumentException( __METHOD__
  77. . ": string too long (length: $length; max: 4294967295)" );
  78. case 'integer':
  79. if ( $value >= 0 ) {
  80. if ( $value <= 0x7F ) {
  81. // positive fixnum
  82. return chr( $value );
  83. }
  84. if ( $value <= 0xFF ) {
  85. // uint8
  86. return pack( 'CC', 0xCC, $value );
  87. }
  88. if ( $value <= 0xFFFF ) {
  89. // uint16
  90. return pack( 'Cn', 0xCD, $value );
  91. }
  92. if ( $value <= 0xFFFFFFFF ) {
  93. // uint32
  94. return pack( 'CN', 0xCE, $value );
  95. }
  96. if ( $value <= 0xFFFFFFFFFFFFFFFF ) {
  97. // uint64
  98. $hi = ( $value & 0xFFFFFFFF00000000 ) >> 32;
  99. $lo = $value & 0xFFFFFFFF;
  100. return self::$bigendian
  101. ? pack( 'CNN', 0xCF, $lo, $hi )
  102. : pack( 'CNN', 0xCF, $hi, $lo );
  103. }
  104. } else {
  105. if ( $value >= -32 ) {
  106. // negative fixnum
  107. return pack( 'c', $value );
  108. }
  109. if ( $value >= -0x80 ) {
  110. // int8
  111. return pack( 'Cc', 0xD0, $value );
  112. }
  113. if ( $value >= -0x8000 ) {
  114. // int16
  115. $p = pack( 's', $value );
  116. return self::$bigendian
  117. ? pack( 'Ca2', 0xD1, $p )
  118. : pack( 'Ca2', 0xD1, strrev( $p ) );
  119. }
  120. if ( $value >= -0x80000000 ) {
  121. // int32
  122. $p = pack( 'l', $value );
  123. return self::$bigendian
  124. ? pack( 'Ca4', 0xD2, $p )
  125. : pack( 'Ca4', 0xD2, strrev( $p ) );
  126. }
  127. if ( $value >= -0x8000000000000000 ) {
  128. // int64
  129. // pack() does not support 64-bit ints either so pack into two 32-bits
  130. $p1 = pack( 'l', $value & 0xFFFFFFFF );
  131. // @phan-suppress-next-line PhanTypeInvalidLeftOperandOfIntegerOp
  132. $p2 = pack( 'l', ( $value >> 32 ) & 0xFFFFFFFF );
  133. return self::$bigendian
  134. ? pack( 'Ca4a4', 0xD3, $p1, $p2 )
  135. : pack( 'Ca4a4', 0xD3, strrev( $p2 ), strrev( $p1 ) );
  136. }
  137. }
  138. throw new InvalidArgumentException( __METHOD__ . ": invalid integer '$value'" );
  139. case 'array':
  140. $buffer = '';
  141. $length = count( $value );
  142. if ( $length > 0xFFFFFFFF ) {
  143. throw new InvalidArgumentException( __METHOD__
  144. . ": array too long (length: $length, max: 4294967295)" );
  145. }
  146. $index = 0;
  147. foreach ( $value as $k => $v ) {
  148. if ( $index !== $k || $index === $length ) {
  149. break;
  150. } else {
  151. $index++;
  152. }
  153. }
  154. $associative = $index !== $length;
  155. if ( $associative ) {
  156. if ( $length < 16 ) {
  157. $buffer .= pack( 'C', 0x80 | $length );
  158. } elseif ( $length <= 0xFFFF ) {
  159. $buffer .= pack( 'Cn', 0xDE, $length );
  160. } else {
  161. $buffer .= pack( 'CN', 0xDF, $length );
  162. }
  163. foreach ( $value as $k => $v ) {
  164. $buffer .= self::pack( $k );
  165. $buffer .= self::pack( $v );
  166. }
  167. } else {
  168. if ( $length < 16 ) {
  169. $buffer .= pack( 'C', 0x90 | $length );
  170. } elseif ( $length <= 0xFFFF ) {
  171. $buffer .= pack( 'Cn', 0xDC, $length );
  172. } else {
  173. $buffer .= pack( 'CN', 0xDD, $length );
  174. }
  175. foreach ( $value as $v ) {
  176. $buffer .= self::pack( $v );
  177. }
  178. }
  179. return $buffer;
  180. default:
  181. throw new InvalidArgumentException( __METHOD__ . ': unsupported type ' . gettype( $value ) );
  182. }
  183. }
  184. }