Skip to content

Commit

Permalink
Implement decoding of 64 bit signed integers (a.k.a. longs) in attrib…
Browse files Browse the repository at this point in the history
…ute tables, fixes #24

Verified by interoperabililty tests with Langohr and the official Java driver that
used java.lang.Long values in headers.
  • Loading branch information
michaelklishin committed Jul 2, 2012
1 parent 8b5fe8c commit 9cf28d1
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 38 deletions.
10 changes: 7 additions & 3 deletions lib/amq/protocol/table.rb
Expand Up @@ -84,9 +84,13 @@ def self.decode(data)
when TYPE_BOOLEAN
v, offset = TableValueDecoder.decode_boolean(data, offset)
v
when TYPE_SIGNED_8BIT then raise NotImplementedError.new
when TYPE_SIGNED_16BIT then raise NotImplementedError.new
when TYPE_SIGNED_64BIT then raise NotImplementedError.new
when TYPE_SIGNED_8BIT then
raise NotImplementedError.new
when TYPE_SIGNED_16BIT then
raise NotImplementedError.new
when TYPE_SIGNED_64BIT then
v, offset = TableValueDecoder.decode_long(data, offset)
v
when TYPE_32BIT_FLOAT then
v, offset = TableValueDecoder.decode_32bit_float(data, offset)
v
Expand Down
98 changes: 63 additions & 35 deletions lib/amq/protocol/table_value_decoder.rb
Expand Up @@ -20,6 +20,10 @@ class TableValueDecoder
# API
#

BIG_ENDIAN = ([1].pack("s") == "\x00\x01")
Q = "Q".freeze


def self.decode_array(data, initial_offset)
array_length = data.slice(initial_offset, 4).unpack(PACK_UINT32).first

Expand All @@ -30,41 +34,47 @@ def self.decode_array(data, initial_offset)
type, offset = decode_value_type(data, offset)

i = case type
when TYPE_STRING
v, offset = decode_string(data, offset)
v
when TYPE_INTEGER
v, offset = decode_integer(data, offset)
v
when TYPE_DECIMAL
v, offset = decode_big_decimal(data, offset)
v
when TYPE_TIME
v, offset = decode_time(data, offset)
v
when TYPE_HASH
v, offset = decode_hash(data, offset)
v
when TYPE_BOOLEAN
v, offset = decode_boolean(data, offset)
v
when TYPE_SIGNED_8BIT then raise NotImplementedError.new
when TYPE_SIGNED_16BIT then raise NotImplementedError.new
when TYPE_SIGNED_64BIT then raise NotImplementedError.new
when TYPE_32BIT_FLOAT then
v, offset = decode_32bit_float(data, offset)
v
when TYPE_64BIT_FLOAT then
v, offset = decode_64bit_float(data, offset)
v
when TYPE_VOID
nil
when TYPE_ARRAY
v, offset = TableValueDecoder.decode_array(data, offset)
v
else
raise ArgumentError.new("unsupported type: #{type.inspect}")
end
when TYPE_STRING
v, offset = decode_string(data, offset)
v
when TYPE_INTEGER
v, offset = decode_integer(data, offset)
v
when TYPE_DECIMAL
v, offset = decode_big_decimal(data, offset)
v
when TYPE_TIME
v, offset = decode_time(data, offset)
v
when TYPE_HASH
v, offset = decode_hash(data, offset)
v
when TYPE_BOOLEAN
v, offset = decode_boolean(data, offset)
v
when TYPE_SIGNED_8BIT then
# TODO
raise NotImplementedError.new
when TYPE_SIGNED_16BIT then
# TODO
raise NotImplementedError.new
when TYPE_SIGNED_64BIT then
v, offset = decode_long(data, offset)
v
when TYPE_32BIT_FLOAT then
v, offset = decode_32bit_float(data, offset)
v
when TYPE_64BIT_FLOAT then
v, offset = decode_64bit_float(data, offset)
v
when TYPE_VOID
nil
when TYPE_ARRAY
v, offset = TableValueDecoder.decode_array(data, offset)
v
else
raise ArgumentError.new("unsupported type in a table value: #{type.inspect}, do not know how to decode!")
end

ary << i
end
Expand Down Expand Up @@ -92,6 +102,24 @@ def self.decode_integer(data, offset)
end # self.decode_integer(data, offset)


if BIG_ENDIAN
def self.decode_long(data, offset)
v = data.slice(offset, 8).unpack(Q)

offset += 8
[v, offset]
end
else
def self.decode_long(data, offset)
slice = data.slice(offset, 8).bytes.to_a.reverse.map(&:chr).join
v = slice.unpack(Q).first

offset += 8
[v, offset]
end
end


def self.decode_big_decimal(data, offset)
decimals, raw = data.slice(offset, 5).unpack(PACK_UCHAR_UINT32)
offset += 5
Expand Down

0 comments on commit 9cf28d1

Please sign in to comment.