* @author Anthon Pang */ class Base64VLQ { // A Base64 VLQ digit can represent 5 bits, so it is base-32. const VLQ_BASE_SHIFT = 5; // A mask of bits for a VLQ digit (11111), 31 decimal. const VLQ_BASE_MASK = 31; // The continuation bit is the 6th bit. const VLQ_CONTINUATION_BIT = 32; /** * Returns the VLQ encoded value. * * @param integer $value * * @return string */ public static function encode($value) { $encoded = ''; $vlq = self::toVLQSigned($value); do { $digit = $vlq & self::VLQ_BASE_MASK; $vlq >>= self::VLQ_BASE_SHIFT; if ($vlq > 0) { $digit |= self::VLQ_CONTINUATION_BIT; } $encoded .= Base64::encode($digit); } while ($vlq > 0); return $encoded; } /** * Decodes VLQValue. * * @param string $str * @param integer $index * * @return integer */ public static function decode($str, &$index) { $result = 0; $shift = 0; do { $c = $str[$index++]; $digit = Base64::decode($c); $continuation = ($digit & self::VLQ_CONTINUATION_BIT) != 0; $digit &= self::VLQ_BASE_MASK; $result = $result + ($digit << $shift); $shift = $shift + self::VLQ_BASE_SHIFT; } while ($continuation); return self::fromVLQSigned($result); } /** * Converts from a two-complement value to a value where the sign bit is * is placed in the least significant bit. For example, as decimals: * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) * * @param integer $value * * @return integer */ private static function toVLQSigned($value) { if ($value < 0) { return ((-$value) << 1) + 1; } return ($value << 1) + 0; } /** * Converts to a two-complement value from a value where the sign bit is * is placed in the least significant bit. For example, as decimals: * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 * * @param integer $value * * @return integer */ private static function fromVLQSigned($value) { $negate = ($value & 1) === 1; $value = $value >> 1; return $negate ? -$value : $value; } }