Former-commit-id:133dc97f67
[formerlya02aeb236c
] [formerly9f19e3f712
] [formerly06a8b51d6d
[formerly9f19e3f712
[formerly 64fa9254b946eae7e61bbc3f513b7c3696c4f54f]]] Former-commit-id:06a8b51d6d
Former-commit-id:377dcd10b9
[formerly3360eb6c5f
] Former-commit-id:8e80217e59
265 lines
4.7 KiB
Ruby
265 lines
4.7 KiB
Ruby
#
|
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
#
|
|
|
|
module Qpid08
|
|
# is there a better way to do this?
|
|
class StringWriter
|
|
|
|
def initialize(str = "")
|
|
@str = str
|
|
end
|
|
|
|
def write(value)
|
|
@str << value
|
|
end
|
|
|
|
def to_s()
|
|
return @str
|
|
end
|
|
|
|
end
|
|
|
|
class EOF < Exception; end
|
|
|
|
class Encoder
|
|
|
|
def initialize(out)
|
|
@out = out
|
|
@bits = []
|
|
end
|
|
|
|
attr_reader(:out)
|
|
|
|
def encode(type, value)
|
|
send(type, value)
|
|
end
|
|
|
|
def bit(b)
|
|
@bits << b
|
|
end
|
|
|
|
def octet(o)
|
|
pack("C", o)
|
|
end
|
|
|
|
def short(s)
|
|
pack("n", s)
|
|
end
|
|
|
|
def long(l)
|
|
pack("N", l)
|
|
end
|
|
|
|
def longlong(l)
|
|
lower = l & 0xffffffff
|
|
upper = (l & ~0xffffffff) >> 32
|
|
long(upper)
|
|
long(lower)
|
|
end
|
|
|
|
def timestamp(l)
|
|
longlong(l)
|
|
end
|
|
|
|
def shortstr(s)
|
|
# shortstr is actually octetstr
|
|
octet(s.length)
|
|
write(s)
|
|
end
|
|
|
|
def longstr(s)
|
|
case s
|
|
when Hash
|
|
table(s)
|
|
else
|
|
long(s.length)
|
|
write(s)
|
|
end
|
|
end
|
|
|
|
def table(t)
|
|
t = {} if t.nil?
|
|
enc = Encoder.new(StringWriter.new())
|
|
t.each {|key, value|
|
|
enc.shortstr(key)
|
|
# I offer this chicken to the gods of polymorphism. May they
|
|
# choke on it.
|
|
case value
|
|
when String
|
|
type = :longstr
|
|
desc = "S"
|
|
when Numeric
|
|
type = :long
|
|
desc = "I"
|
|
else
|
|
raise Exception.new("unknown table value: #{value.class}")
|
|
end
|
|
enc.write(desc)
|
|
enc.encode(type, value)
|
|
}
|
|
longstr(enc.out.to_s())
|
|
end
|
|
|
|
def write(str)
|
|
flushbits()
|
|
@out.write(str)
|
|
# puts "OUT #{str.inspect()}"
|
|
end
|
|
|
|
def pack(fmt, *args)
|
|
write(args.pack(fmt))
|
|
end
|
|
|
|
def flush()
|
|
flushbits()
|
|
end
|
|
|
|
private
|
|
|
|
def flushbits()
|
|
if @bits.empty? then return end
|
|
|
|
bytes = []
|
|
index = 0
|
|
@bits.each {|b|
|
|
bytes << 0 if index == 0
|
|
if b then bytes[-1] |= 1 << index end
|
|
index = (index + 1) % 8
|
|
}
|
|
@bits.clear()
|
|
bytes.each {|b|
|
|
octet(b)
|
|
}
|
|
end
|
|
|
|
end
|
|
|
|
class StringReader
|
|
|
|
def initialize(str)
|
|
@str = str
|
|
@index = 0
|
|
end
|
|
|
|
def read(n)
|
|
result = @str[@index, n]
|
|
@index += result.length
|
|
return result
|
|
end
|
|
|
|
end
|
|
|
|
class Decoder
|
|
|
|
def initialize(_in)
|
|
@in = _in
|
|
@bits = []
|
|
end
|
|
|
|
def decode(type)
|
|
return send(type)
|
|
end
|
|
|
|
def bit()
|
|
if @bits.empty?
|
|
byte = octet()
|
|
7.downto(0) {|i|
|
|
@bits << (byte[i] == 1)
|
|
}
|
|
end
|
|
return @bits.pop()
|
|
end
|
|
|
|
def octet()
|
|
return unpack("C", 1)
|
|
end
|
|
|
|
def short()
|
|
return unpack("n", 2)
|
|
end
|
|
|
|
def long()
|
|
return unpack("N", 4)
|
|
end
|
|
|
|
def longlong()
|
|
upper = long()
|
|
lower = long()
|
|
return upper << 32 | lower
|
|
end
|
|
|
|
def timestamp()
|
|
return longlong()
|
|
end
|
|
|
|
def shortstr()
|
|
# shortstr is actually octetstr
|
|
return read(octet())
|
|
end
|
|
|
|
def longstr()
|
|
return read(long())
|
|
end
|
|
|
|
def table()
|
|
dec = Decoder.new(StringReader.new(longstr()))
|
|
result = {}
|
|
while true
|
|
begin
|
|
key = dec.shortstr()
|
|
rescue EOF
|
|
break
|
|
end
|
|
desc = dec.read(1)
|
|
case desc
|
|
when "S"
|
|
value = dec.longstr()
|
|
when "I"
|
|
value = dec.long()
|
|
else
|
|
raise Exception.new("unrecognized descriminator: #{desc.inspect()}")
|
|
end
|
|
result[key] = value
|
|
end
|
|
return result
|
|
end
|
|
|
|
def read(n)
|
|
return "" if n == 0
|
|
result = @in.read(n)
|
|
if result.nil? or result.empty?
|
|
raise EOF.new()
|
|
else
|
|
# puts " IN #{result.inspect()}"
|
|
return result
|
|
end
|
|
end
|
|
|
|
def unpack(fmt, size)
|
|
result = read(size).unpack(fmt)
|
|
if result.length == 1
|
|
return result[0]
|
|
else
|
|
return result
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|