summaryrefslogtreecommitdiff
path: root/qpid/ruby/lib/qpid/codec08.rb
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/ruby/lib/qpid/codec08.rb')
-rw-r--r--qpid/ruby/lib/qpid/codec08.rb265
1 files changed, 265 insertions, 0 deletions
diff --git a/qpid/ruby/lib/qpid/codec08.rb b/qpid/ruby/lib/qpid/codec08.rb
new file mode 100644
index 0000000000..148dee07bb
--- /dev/null
+++ b/qpid/ruby/lib/qpid/codec08.rb
@@ -0,0 +1,265 @@
+#
+# 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