VarInt.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #include "mumlib/VarInt.hpp"
  2. #include <boost/format.hpp>
  3. mumlib::VarInt::VarInt(int64_t value) : value(value) { }
  4. mumlib::VarInt::VarInt(uint8_t *encoded) : value(parseVariant(encoded)) { }
  5. mumlib::VarInt::VarInt(std::vector<uint8_t> encoded) : value(parseVariant(&encoded[0])) { }
  6. /*
  7. * This code was taken from Mumble source code
  8. * https://github.com/mumble-voip/mumble/blob/master/src/PacketDataStream.h
  9. */
  10. int64_t mumlib::VarInt::parseVariant(const uint8_t *buffer) {
  11. int64_t v = buffer[0];
  12. if ((v & 0x80) == 0x00) {
  13. return (v & 0x7F);
  14. } else if ((v & 0xC0) == 0x80) {
  15. return (v & 0x3F) << 8 | buffer[1];
  16. } else if ((v & 0xF0) == 0xF0) {
  17. switch (v & 0xFC) {
  18. case 0xF0:
  19. return buffer[1] << 24 | buffer[2] << 16 | buffer[3] << 8 | buffer[4];
  20. case 0xF4:
  21. throw VarIntException("currently unsupported 8-byte varint size");
  22. case 0xF8:
  23. case 0xFC:
  24. throw VarIntException("currently negative varints aren't supported");
  25. default:
  26. break;
  27. }
  28. } else if ((v & 0xF0) == 0xE0) {
  29. return (v & 0x0F) << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
  30. } else if ((v & 0xE0) == 0xC0) {
  31. return (v & 0x1F) << 16 | buffer[1] << 8 | buffer[2];
  32. }
  33. throw VarIntException("invalid varint");
  34. }
  35. std::vector<uint8_t> mumlib::VarInt::getEncoded() const {
  36. std::vector<uint8_t> encoded;
  37. int64_t i = this->value;
  38. if ((i & 0x8000000000000000LL) && (~i < 0x100000000LL)) {
  39. i = ~i;
  40. if (i <= 0x3) {
  41. encoded.push_back(static_cast<unsigned char &&>(0xFC | i));
  42. return encoded;
  43. } else {
  44. encoded.push_back(0xF8);
  45. }
  46. }
  47. if (i < 0x80) {
  48. encoded.push_back(static_cast<unsigned char &&>(i));
  49. } else if (i < 0x4000) {
  50. encoded.push_back(static_cast<unsigned char &&>(0x80 | (i >> 8)));
  51. encoded.push_back(static_cast<unsigned char &&>(i & 0xFF));
  52. } else if (i < 0x200000) {
  53. encoded.push_back(static_cast<unsigned char &&>(0xC0 | (i >> 16)));
  54. encoded.push_back(static_cast<unsigned char &&>((i >> 8) & 0xFF));
  55. encoded.push_back(static_cast<unsigned char &&>(i & 0xFF));
  56. } else if (i < 0x10000000) {
  57. encoded.push_back(static_cast<unsigned char &&>(0xE0 | (i >> 24)));
  58. encoded.push_back(static_cast<unsigned char &&>((i >> 16) & 0xFF));
  59. encoded.push_back(static_cast<unsigned char &&>((i >> 8) & 0xFF));
  60. encoded.push_back(static_cast<unsigned char &&>(i & 0xFF));
  61. } else {
  62. encoded.push_back(0xF4);
  63. encoded.push_back(static_cast<unsigned char &&>((i >> 56) & 0xFF));
  64. encoded.push_back(static_cast<unsigned char &&>((i >> 48) & 0xFF));
  65. encoded.push_back(static_cast<unsigned char &&>((i >> 40) & 0xFF));
  66. encoded.push_back(static_cast<unsigned char &&>((i >> 32) & 0xFF));
  67. encoded.push_back(static_cast<unsigned char &&>((i >> 24) & 0xFF));
  68. encoded.push_back(static_cast<unsigned char &&>((i >> 16) & 0xFF));
  69. encoded.push_back(static_cast<unsigned char &&>((i >> 8) & 0xFF));
  70. encoded.push_back(static_cast<unsigned char &&>(i & 0xFF));
  71. }
  72. return encoded;
  73. }