2015-08-19 37 views
1

我正在嘗試編寫Go程序來解析ans.1 BER二進制補碼整數編碼。但是,整數可以具有1,2,3或4字節長度編碼(取決於其大小)。int64的可變長度二進制補碼

根據規範(http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf),最左邊的位總是補碼。

什麼是乾淨的方式來做到這一點?

func ParseInt(b []byte) (int64, error) { 
    switch len(b) { 
    case 1: 
     // this works 
     return int64(b[0]&0x7f) - int64(b[0]&0x80), nil 
    case 2: 
     // left most byte of b[0] is -32768 
    case 3: 
     // left most byte of b[0] is -8388608 
    case 4: 
     // left most byte of b[0] is -2147483648 (and so on for 5, 6, 7, 8) 
    case 5: 
    case 6: 
    case 7: 
    case 8: 
    default: 
     return 0, errors.New("value does not fit in a int64") 
    } 
} 


ParseInt([]byte{0xfe})  // should return (-2, nil) 
ParseInt([]byte{0xfe, 0xff}) // should return (-257, nil) 
ParseInt([]byte{0x01, 0x00}) // should return (256, nil) 
+0

這將是一個很大的幫助,如果你引述確切規則從規範分析。理想情況下,用'//如何處理這個?'替換'//得到低位字節,...'。 –

回答

2

更容易,如果你從終端讀取的字節數就明白了:

  • 您不必到最後一個字節
  • 的最後一個字節由8(8位左移移一個字節)
  • 左移16
  • 二號最後一個字節...
  • 而且從第一個字節只使用7位,最左邊的一位是特別的。

第一個字節b[0]&080的最左邊的位表示是否必須向結果添加偏移量。可選擇添加的偏移量爲-1乘以輸入意義的數字,通過設置此一位而所有其他值爲0-1 * (1 << (len(b)*8 - 1)) = 0x80 << (len(b)*8 - 8)

例子。如果輸入是...

  • 1字節:
    int64(b[0]&0x7f) - int64(b[0]&0x80)
  • 2字節:
    int64(b[0]&0x7f)<<8 + int64(b[1]) - int64(b[0]&0x80)<<8
  • 3個字節:
    int64(b[0]&0x7f)<<16 + int64(b[1])<<8 + int64(b[2]) - int64(b[0]&0x80)<<16

所有這些情況下,可以覆蓋有一個不錯的循環。

這裏是一個緊湊的實現(嘗試在Go Playground):

func ParseInt(b []byte) (int64, error) { 
    if len(b) > 8 { 
     return 0, errors.New("value does not fit in a int64") 
    } 

    var n int64 
    for i, v := range b { 
     shift := uint((len(b) - i - 1) * 8) 
     if i == 0 && v&0x80 != 0 { 
      n -= 0x80 << shift 
      v &= 0x7f 
     } 
     n += int64(v) << shift 
    } 
    return n, nil 
} 
+0

真棒,謝謝!這是'n - = 0x80 << shift',真的讓我感到沮喪 –