class CBOR::Buffer
Constants
- HALF_NAN_BYTES
- MT_NAMES
- MT_TO_ENCODING
Attributes
buffer[R]
Public Class Methods
new(s = String.new)
click to toggle source
# File lib/cbor-pure.rb, line 99 def initialize(s = String.new) @buffer = s @pos = 0 end
Public Instance Methods
add(d)
click to toggle source
# File lib/cbor-pure.rb, line 150 def add(d) case d when Integer ib = if d < 0 d = -1-d 0x20 else 0x00 end head(ib, d) { # block is called if things do not fit s = bignum_to_bytes(d) head(0xc0, TAG_BIGNUM_BASE + (ib >> 5)) head(0x40, s.bytesize) s } when Numeric; addfloat(d) when Symbol; add(d.to_s) # hack: this should really be tagged when Simple; head(0xe0, d.value) when false; head(0xe0, 20) when true; head(0xe0, 21) when nil; head(0xe0, 22) when Tagged # we don't handle :simple here head(0xc0, d.tag) add(d.value) when String lengths = d.cbor_stream? e = d ib = if d.encoding == Encoding::BINARY 0x40 else d = d.encode(Encoding::UTF_8).force_encoding(Encoding::BINARY) 0x60 end if lengths @buffer << (ib + 31) pos = 0 lengths.each do |r| add(e[pos, r]) pos += r end @buffer << 0xff else head(ib, d.bytesize) @buffer << d end when Array if d.cbor_stream? @buffer << 0x9f d.each {|di| add(di)} @buffer << 0xff else head(0x80, d.size) d.each {|di| add(di)} end when Hash if d.cbor_stream? @buffer << 0xbf d.each {|k, v| add(k); add(v)} @buffer << 0xff else head(0xa0, d.size) d.each {|k, v| add(k); add(v)} end else raise("Don't know how to encode #{d.inspect}") end self end
addfloat(fv)
click to toggle source
# File lib/cbor-pure.rb, line 124 def addfloat(fv) if fv.nan? @buffer << HALF_NAN_BYTES else ss = [fv].pack("g") # single-precision if ss.unpack("g").first == fv if hs = Half.encode_from_single(fv, ss) @buffer << 0xf9 << hs else @buffer << 0xfa << ss end else @buffer << [0xfb, fv].pack("CG") # double-precision end end end
atleast(n)
click to toggle source
# File lib/cbor-pure.rb, line 219 def atleast(n) left = @buffer.bytesize - @pos raise OutOfBytesError.new(n - left) if n > left end
bignum_to_bytes(d)
click to toggle source
# File lib/cbor-pure.rb, line 141 def bignum_to_bytes(d) s = String.new while (d != 0) s << (d & 0xFF) d >>= 8 end s.reverse! end
decode_item(breakable = false)
click to toggle source
# File lib/cbor-pure.rb, line 263 def decode_item(breakable = false) ib = take(1).ord ai = ib & 0x1F val = case ai when 0...24; ai when 24; take(1).ord when 25; take(2).unpack("n").first when 26; (s = take(4)).unpack("N").first when 27; (s = take(8)).unpack("Q>").first when 31; return decode_item_streaming(ib, breakable) else raise "unknown additional information #{ai} in ib #{ib}" end case ib >>= 5 when 0; val when 1; -1-val when 7 case ai when 20; false when 21; true when 22; nil # when 23; Simple.new(23) # Ruby does not have Undefined when 24; raise "two-byte simple is #{val} but must be between 32 and 255" unless val >= 32; Simple.new(val) when 25; Half.decode(val) when 26; s.unpack("g").first # cannot go directly from val when 27; s.unpack("G").first # in Ruby else Simple.new(val) end when 6 di = decode_item if String === di && (val & ~1) == TAG_BIGNUM_BASE (TAG_BIGNUM_BASE - val) ^ di.bytes.inject(0) {|sum, b| sum <<= 8; sum += b } else Tagged.new(val, di) end when 2; take(val).force_encoding(Encoding::BINARY) when 3; take(val).force_encoding(Encoding::UTF_8) when 4; atleast(val); Array.new(val) { decode_item } when 5; atleast(val<<1); Hash[Array.new(val) {[decode_item, decode_item]}] end end
decode_item_final()
click to toggle source
# File lib/cbor-pure.rb, line 307 def decode_item_final val = decode_item raise "extra bytes follow after a deserialized object of #@pos bytes" if @pos != @buffer.size val end
decode_item_streaming(ib, breakable)
click to toggle source
# File lib/cbor-pure.rb, line 233 def decode_item_streaming(ib, breakable) case ib >>= 5 when 2, 3 want_encoding = MT_TO_ENCODING[ib] subs = [] while (element = decode_item(true)) != BREAK raise "non-string (#{element.inspect}) in streaming string" unless String === element raise "bytes/text mismatch (#{element.encoding} != #{want_encoding}) in streaming string" unless element.encoding == want_encoding subs << element end result = subs.join.cbor_stream!(subs.map(&:length)).force_encoding(want_encoding) when 4 result = Array.new; while (element = decode_item(true)) != BREAK result << element end result when 5 result = Hash.new while (key = decode_item(true)) != BREAK result[key] = decode_item end result when 7 raise "break stop code outside indefinite length item" unless breakable BREAK else raise "unknown ib #{ib} for additional information 31" end end
decode_item_with_rest()
click to toggle source
# File lib/cbor-pure.rb, line 313 def decode_item_with_rest val = decode_item [val, @buffer[@pos..-1]] end
decode_items()
click to toggle source
# File lib/cbor-pure.rb, line 318 def decode_items ret = [] while @pos != buffer.size ret << decode_item end ret end
empty?()
click to toggle source
# File lib/cbor-pure.rb, line 326 def empty? @pos == buffer.size end
head(ib, n) { || ... }
click to toggle source
# File lib/cbor-pure.rb, line 104 def head(ib, n) @buffer << case n when 0...24 [ib + n].pack("C") when 0...256 [ib + 24, n].pack("CC") when 0...65536 [ib + 25, n].pack("Cn") when 0...4294967296 [ib + 26, n].pack("CN") when 0...18446744073709551616 [ib + 27, n].pack("CQ>") else yield # throw back to caller end end
pretty_item()
click to toggle source
# File lib/cbor-pretty.rb, line 54 def pretty_item ib = take_and_print(1, ' ' * @indent).ord ai = ib & 0x1F val = case ai when 0...24; ai when 24; take_and_print(1, ' ').ord when 25; take_and_print(2, ' ').unpack("n").first when 26; (s = take_and_print(4, ' ')).unpack("N").first when 27; (s = take_and_print(8, ' ')).unpack("Q>").first when 31; return pretty_item_streaming(ib) else raise "unknown additional information #{ai} in ib #{ib}" end @out << " # #{MT_NAMES[ib >> 5]}(#{val})\n" @indent += 1 case ib >>= 5 when 6 pretty_item when 2, 3 @out << ' ' * (@indent) s = take_and_print(val) @out << " # #{s.inspect}" @out << "\n" when 4; val.times { pretty_item } when 5; val.times { pretty_item; pretty_item} end @indent -= 1 nil end
pretty_item_final(indent = 0, max_target = 40, seq = false)
click to toggle source
# File lib/cbor-pretty.rb, line 83 def pretty_item_final(indent = 0, max_target = 40, seq = false) @out = '' @indent = indent pretty_item unless seq raise if @pos != @buffer.size end target = [@out.each_line.map {|ln| ln =~ /#/ || 0}.max, max_target].min @out.each_line.map {|ln| col = ln =~ /#/ if col && col < target ln[col, 0] = ' ' * (target - col) end ln }.join end
pretty_item_streaming(ib)
click to toggle source
# File lib/cbor-pretty.rb, line 37 def pretty_item_streaming(ib) res = nil @out << " # #{MT_NAMES[ib >> 5]}(*)\n" @indent += 1 case ib >>= 5 when 2, 3, 4, 5 while (element = pretty_item) != BREAK end when 7; res = BREAK else raise "unknown ib #{ib} for additional information 31" end @indent -= 1 res end
take(n)
click to toggle source
# File lib/cbor-pure.rb, line 224 def take(n) opos = @pos @pos += n raise OutOfBytesError.new(@pos - @buffer.bytesize) if @pos > @buffer.bytesize @buffer[opos, n] end
take_and_print(n, prefix = '')
click to toggle source
# File lib/cbor-pretty.rb, line 30 def take_and_print(n, prefix = '') s = take(n) @out << prefix @out << s.hexbytes s end