Module: Protobug::BinaryEncoding

Defined in:
lib/protobug/binary_encoding.rb

Class Method Summary collapse

Class Method Details

.decode_length(binary) ⇒ Object

Raises:

  • (EOFError)


63
64
65
66
67
68
69
# File 'lib/protobug/binary_encoding.rb', line 63

def decode_length(binary)
  length = decode_varint(binary) || raise(EOFError, "unexpected EOF")
  string = binary.read(length) || raise(EOFError, "unexpected EOF")
  raise EOFError, "expected #{length} bytes, got #{string.bytesize}" unless string.bytesize == length

  string
end

.decode_varint(binary) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/protobug/binary_encoding.rb', line 46

def decode_varint(binary)
  byte = binary.getbyte
  return unless byte

  value = 0
  bl = 0
  loop do
    raise DecodeError, "varint too large" if bl > 63
    return value if byte.nil?
    return value | (byte << bl) if (byte & 0b1000_0000).zero? # no continuation bit set

    value |= ((byte & 0b0111_1111) << bl)
    bl += 7
    byte = binary.getbyte || raise(EOFError, "unexpected EOF")
  end
end

.decode_zigzag(size, value) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/protobug/binary_encoding.rb', line 71

def decode_zigzag(size, value)
  negative = value & 1 == 1
  value %= 2**size
  value >>= 1
  value = -value - 1 if negative

  unless value.bit_length <= size
    raise DecodeError,
          "bitlength too large for #{size}-bit integer: #{value.bit_length}"
  end

  value
end

.encode_length(contents, outbuf) ⇒ Object



41
42
43
44
# File 'lib/protobug/binary_encoding.rb', line 41

def encode_length(contents, outbuf)
  encode_varint contents.bytesize, outbuf
  outbuf << contents
end

.encode_varint(value, outbuf) ⇒ Object

Raises:



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/protobug/binary_encoding.rb', line 9

def encode_varint(value, outbuf)
  raise EncodeError, "expected integer, got #{value.inspect}" unless value.is_a? Integer
  raise RangeError, "expected 64-bit integer" if value > (2**64) - 1 || value < -2**63

  negative = value.negative?
  value = (2**64) + value if negative
  out = []
  loop do
    if value.bit_length > 7
      out << (0b1000_0000 | (value & 0b0111_1111))
      value >>= 7
    else
      out << (value & 0b0111_1111)
      break
    end
  end
  out.pack("c*", buffer: outbuf)
end

.encode_zigzag(size, value, outbuf) ⇒ Object

Raises:



28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/protobug/binary_encoding.rb', line 28

def encode_zigzag(size, value, outbuf)
  raise EncodeError, "expected integer, got #{value.inspect}" unless value.is_a? Integer

  unless value.bit_length <= size
    raise EncodeError,
          "bitlength too large for #{size}-bit integer: #{value.bit_length}"
  end

  encoded = 2 * value.abs
  encoded -= 1 if value.negative?
  encode_varint encoded, outbuf
end

.read_field_value(binary, wire_type) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/protobug/binary_encoding.rb', line 85

def read_field_value(binary, wire_type)
  case wire_type
  when 0
    decode_varint(binary) || raise(EOFError, "unexpected EOF")
  when 1
    value = binary.read(8)
    raise EOFError, "unexpected EOF" if value&.bytesize != 8

    value
  when 2
    decode_length(binary)
  when 3, 4
    raise UnsupportedFeatureError.new(:group, "reading groups from binary protos (in #{self})")
  when 5
    value = binary.read(4)
    raise EOFError, "unexpected EOF" if value&.bytesize != 4

    value
  else
    raise DecodeError, "unknown wire_type: #{wire_type}"
  end
end