2013-11-03 26 views
5

Ben C/C++ linux yuvalarından bir VarInts okumak gerekir. Herhangi bir kütüphane, fikir falan var mı?Oku "VarInt"

Ayrıca, bu yeni Minecraft 1.7.2 haberleşme protokolü ile uyumluluk içindir

Okumayı ve [8] Bir VARINT okumaya başarılı olamadı denemek için bool kömürü döküm çalıştı

... Böylece, the documentation of the protocol da olabilir yardım et. (... java çok yavaş olduğu için) benim VPS çalıştırmak için bir Minecraft sunucu yazılımını yapıyorum ve ben protokolü ile sıkışmış:

beni projemi açıklayayım. Bir iplik bağlantıları için bekler ve yeni bir bağlantı olduğunda, yeni bir istemci nesnesi yaratır ve müşteri ile iletişim başlar Müşteri parçacığı başlar.

Ben kodunu göstermek için gerek yoktur diye düşünüyorum. Yanlış olduğumda, bana söyle ve bende bir kodla düzenleyeceğim.

+2

önce varints ama "VarInt c kütüphanesinde" için google çalıştı ve birkaç darbe aldık. Bu büyük cevap için –

cevap

11

İlk kapalı, varyasyonların gerçek bayt olarak gönderildiğini, 1 ve 0 karakterlerinin dizelerini değil.

İmzasız bir varyant için, data ile işaretlenmiş bir arabellekte varyant verilerini aldığınızı varsayarak, aşağıdakilerin sizin için şifresini çözeceğine inanıyorum. Bu örnek işlevi, int decoded_bytes referans argümanında çözülen bayt sayısını döndürür.

uint64_t decode_unsigned_varint(const uint8_t *const data, int &decoded_bytes) 
{ 
    int i = 0; 
    uint64_t decoded_value = 0; 
    int shift_amount = 0; 

    do 
    { 
     decoded_value |= (uint64_t)(data[i] & 0x7F) << shift_amount;  
     shift_amount += 7; 
    } while ((data[i++] & 0x80) != 0); 

    decoded_bytes = i; 
    return decoded_value; 
} 

imzalı VARINT deşifre etmek için önce çağıran bu ikinci işlevi kullanabilirsiniz:

int64_t decode_signed_varint(const uint8_t *const data, int &decoded_bytes) 
{ 
    uint64_t unsigned_value = decode_unsigned_varint(data, decoded_bytes); 
    return (int64_t)(unsigned_value & 1 ? ~(unsigned_value >> 1) 
             : (unsigned_value >> 1)); 
} 

Ben bu fonksiyonların her ikisi doğru olduğuna inanıyoruz. Google sayfasından birkaç veri noktasını doğrulamak için aşağıdaki kodla bazı temel testler yaptım. Çıkış doğru.

#include <stdint.h> 
#include <iostream> 


uint64_t decode_unsigned_varint(const uint8_t *const data, int &decoded_bytes) 
{ 
    int i = 0; 
    uint64_t decoded_value = 0; 
    int shift_amount = 0; 

    do 
    { 
     decoded_value |= (uint64_t)(data[i] & 0x7F) << shift_amount;  
     shift_amount += 7; 
    } while ((data[i++] & 0x80) != 0); 

    decoded_bytes = i; 
    return decoded_value; 
} 

int64_t decode_signed_varint(const uint8_t *const data, int &decoded_bytes) 
{ 
    uint64_t unsigned_value = decode_unsigned_varint(data, decoded_bytes); 
    return (int64_t)(unsigned_value & 1 ? ~(unsigned_value >> 1) 
             : (unsigned_value >> 1)); 
} 



uint8_t ex_p300[] = { 0xAC, 0x02 }; 
uint8_t ex_n1 [] = { 0x01 }; 

using namespace std; 

int main() 
{ 
    int decoded_bytes_p300; 
    uint64_t p300; 

    p300 = decode_unsigned_varint(ex_p300, decoded_bytes_p300); 

    int decoded_bytes_n1; 
    int64_t n1; 

    n1 = decode_signed_varint(ex_n1, decoded_bytes_n1); 

    cout << "p300 = " << p300 
     << " decoded_bytes_p300 = " << decoded_bytes_p300 << endl; 

    cout << "n1 = " << n1 
     << " decoded_bytes_n1 = " << decoded_bytes_n1 << endl; 

    return 0; 
} 

Değişiklikleri kodlamak için aşağıdaki işlevleri kullanabilirsiniz. büyük VarInt 10 bayt uzunluğunda olduğu gibi tampon uint8_t *const data, en az 10 baytlık bir yere sahip olduğunu unutmayın.
#include hiç görmedim

// Encode an unsigned 64-bit varint. Returns number of encoded bytes. 
// 'buffer' must have room for up to 10 bytes. 
int encode_unsigned_varint(uint8_t *const buffer, uint64_t value) 
{ 
    int encoded = 0; 

    do 
    { 
     uint8_t next_byte = value & 0x7F; 
     value >>= 7; 

     if (value) 
      next_byte |= 0x80; 

     buffer[encoded++] = next_byte; 

    } while (value); 


    return encoded; 
} 

// Encode a signed 64-bit varint. Works by first zig-zag transforming 
// signed value into an unsigned value, and then reusing the unsigned 
// encoder. 'buffer' must have room for up to 10 bytes. 
int encode_signed_varint(uint8_t *const buffer, int64_t value) 
{ 
    uint64_t uvalue; 

    uvalue = uint64_t(value < 0 ? ~(value << 1) : (value << 1)); 

    return encode_unsigned_varint(buffer, uvalue); 
} 
+1

teşekkürler. Belki konu dışıyım ama nasıl kodlarım? Ben biraz operatörlerine bir göz gerektiğini düşünüyorum ... – azteca1998

+1

Encode deşifre benzer. Bir çift kodlama fonksiyonunu çalacak ve oraya atacağım. –

+0

Tekrar teşekkürler! 10 bayt ayırmaya gerek duymuyorum çünkü işlevi, inşa edildiği şekilde varintiyi gönderecek şekilde uyarlarım. Fonksiyon, döngüye her adımda istemciye 1 bayt gönderecektir. – azteca1998