hessian2 1.1.1 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +6 -2
- data/LICENSE.txt +22 -0
- data/README.md +161 -0
- data/hessian2.gemspec +3 -2
- data/lib/hessian2.rb +12 -4
- data/lib/hessian2/class_wrapper.rb +89 -0
- data/lib/hessian2/client.rb +38 -0
- data/lib/hessian2/constants.rb +164 -0
- data/lib/hessian2/em_client.rb +52 -0
- data/lib/hessian2/fault.rb +3 -0
- data/lib/hessian2/handler.rb +15 -0
- data/lib/hessian2/hessian_client.rb +3 -38
- data/lib/hessian2/parser.rb +619 -0
- data/lib/hessian2/struct_wrapper.rb +55 -0
- data/lib/hessian2/type_wrapper.rb +49 -8
- data/lib/hessian2/version.rb +1 -1
- data/lib/hessian2/writer.rb +498 -0
- data/spec/binary_spec.rb +51 -0
- data/spec/boolean_spec.rb +26 -0
- data/spec/class_wrapper_spec.rb +52 -0
- data/spec/create_monkeys.rb +14 -0
- data/spec/date_spec.rb +45 -0
- data/spec/double_spec.rb +78 -0
- data/spec/int_spec.rb +54 -0
- data/spec/list_spec.rb +66 -0
- data/spec/long_spec.rb +68 -0
- data/spec/map_spec.rb +36 -0
- data/spec/null_spec.rb +17 -0
- data/spec/object_spec.rb +65 -0
- data/spec/ref_spec.rb +43 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/string_spec.rb +61 -0
- data/spec/struct_wrapper_spec.rb +47 -0
- data/spec/type_wrapper_spec.rb +102 -0
- data/test/app.rb +15 -0
- data/test/client.rb +9 -0
- data/test/config.ru +2 -0
- data/test/monkey_service.rb +12 -0
- metadata +79 -19
- data/README.rdoc +0 -21
- data/lib/hessian2/hessian_exception.rb +0 -3
- data/lib/hessian2/hessian_parser.rb +0 -75
- data/lib/hessian2/hessian_writer.rb +0 -130
- data/test/test_hessian_parser.rb +0 -56
| @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            require 'uri'
         | 
| 2 | 
            +
            require 'em-synchrony'
         | 
| 3 | 
            +
            require 'em-synchrony/em-http'
         | 
| 4 | 
            +
            require 'hessian2'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Hessian2
         | 
| 7 | 
            +
              class EmClient
         | 
| 8 | 
            +
                attr_accessor :user, :password
         | 
| 9 | 
            +
                attr_reader :scheme, :host, :port, :path, :proxy
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize(url, proxy = {})
         | 
| 12 | 
            +
                  uri = URI.parse(url)
         | 
| 13 | 
            +
                  @scheme, @host, @port, @path = uri.scheme, uri.host, uri.port, uri.path.empty? ? '/' : uri.path
         | 
| 14 | 
            +
                  @path += "?#{uri.query}" if uri.query
         | 
| 15 | 
            +
                  raise "Unsupported Hessian protocol: #{@scheme}" unless @scheme == 'http'
         | 
| 16 | 
            +
                  @proxy = proxy
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
             | 
| 20 | 
            +
                def method_missing(id, *args)
         | 
| 21 | 
            +
                  return invoke(id.id2name, args)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
             | 
| 25 | 
            +
                private
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def invoke(method, args)
         | 
| 28 | 
            +
                  result = nil
         | 
| 29 | 
            +
                  block = lambda do
         | 
| 30 | 
            +
                    EM::Synchrony.sync(
         | 
| 31 | 
            +
                      EM::HttpRequest.new("http://#{@host}:#{@port}", :connect_timeout => 5, :inactivity_timeout => 60).post(
         | 
| 32 | 
            +
                        path: @path,
         | 
| 33 | 
            +
                        head: {'Content-Type' => 'application/binary; charset=utf-8'},
         | 
| 34 | 
            +
                        body: Hessian2.call(method, args)
         | 
| 35 | 
            +
                      )
         | 
| 36 | 
            +
                    )
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  unless EM.reactor_running?
         | 
| 40 | 
            +
                    EM.synchrony do
         | 
| 41 | 
            +
                      result = Hessian2.parse_rpc(block.call.response)
         | 
| 42 | 
            +
                      EM.stop
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
                  else
         | 
| 45 | 
            +
                    result = Hessian2.parse_rpc(block.call.response)
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  result
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            require 'hessian2'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Hessian2
         | 
| 4 | 
            +
              module Handler
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def handle(data)
         | 
| 7 | 
            +
                  begin
         | 
| 8 | 
            +
                    Hessian2.reply(self.send(*Hessian2.parse_rpc(data)))
         | 
| 9 | 
            +
                  rescue NoMethodError, ArgumentError, NameError, Fault => e
         | 
| 10 | 
            +
                    Hessian2.write_fault(e)
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -1,38 +1,3 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 3 | 
            -
             | 
| 4 | 
            -
            require 'hessian2/hessian_writer'
         | 
| 5 | 
            -
            require 'hessian2/hessian_parser'
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            module Hessian2
         | 
| 8 | 
            -
              class HessianClient
         | 
| 9 | 
            -
                attr_accessor :user, :password
         | 
| 10 | 
            -
                attr_reader :scheme, :host, :port, :path, :proxy
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                include HessianWriter
         | 
| 13 | 
            -
                include HessianParser
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                def initialize(url, proxy = {})
         | 
| 16 | 
            -
                  uri = URI.parse(url)
         | 
| 17 | 
            -
                  @scheme, @host, @port, @path = uri.scheme, uri.host, uri.port, uri.path
         | 
| 18 | 
            -
                  raise "Unsupported Hessian protocol: #{@scheme}" unless %w(http https).include? @scheme
         | 
| 19 | 
            -
                  @proxy = proxy
         | 
| 20 | 
            -
                end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                def method_missing(id, *args)
         | 
| 23 | 
            -
                  return invoke(id.id2name, args)
         | 
| 24 | 
            -
                end
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                private
         | 
| 27 | 
            -
                def invoke(method, args)
         | 
| 28 | 
            -
                  req = Net::HTTP::Post.new(@path, { 'Content-Type' => 'application/binary' })
         | 
| 29 | 
            -
                  req.basic_auth @user, @password if @user
         | 
| 30 | 
            -
                  conn = Net::HTTP.new(@host, @port, *@proxy.values_at(:host, :port, :user, :password))
         | 
| 31 | 
            -
                  conn.use_ssl = true and conn.verify_mode = OpenSSL::SSL::VERIFY_NONE if @scheme == 'https'
         | 
| 32 | 
            -
                  conn.start do |http|
         | 
| 33 | 
            -
                    parse http.request(req, write_call(method, args)).body
         | 
| 34 | 
            -
                  end
         | 
| 35 | 
            -
                end
         | 
| 36 | 
            -
             | 
| 37 | 
            -
              end
         | 
| 38 | 
            -
            end
         | 
| 1 | 
            +
            module Hessian2
         | 
| 2 | 
            +
              class HessianClient < Client; end
         | 
| 3 | 
            +
            end
         | 
| @@ -0,0 +1,619 @@ | |
| 1 | 
            +
            require 'hessian2/constants'
         | 
| 2 | 
            +
            require 'hessian2/fault'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Hessian2
         | 
| 5 | 
            +
              module Parser
         | 
| 6 | 
            +
                include Constants
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def parse_rpc(data)
         | 
| 9 | 
            +
                  bytes = data.each_byte
         | 
| 10 | 
            +
                  bc = bytes.next
         | 
| 11 | 
            +
                  if bc == 0x48 # skip hessian version
         | 
| 12 | 
            +
                    2.times{ bytes.next }
         | 
| 13 | 
            +
                    bc = bytes.next
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  case bc
         | 
| 17 | 
            +
                  when 0x43 # rpc call ('C')
         | 
| 18 | 
            +
                    method = parse_string(bytes)
         | 
| 19 | 
            +
                    refs, cdefs = [], []
         | 
| 20 | 
            +
                    args = [].tap do |arr|
         | 
| 21 | 
            +
                      parse_int(bytes).times{ arr << parse_bytes(bytes, nil, {}, refs, cdefs) }
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
                    [ method, *args ]
         | 
| 24 | 
            +
                  when 0x46 # fault ('F')
         | 
| 25 | 
            +
                    fault = parse_bytes(bytes)
         | 
| 26 | 
            +
                    code, message = fault['code'], fault['message']
         | 
| 27 | 
            +
                    raise Fault.new, code == 'RuntimeError' ? message : "#{code} - #{message}"
         | 
| 28 | 
            +
                  when 0x52 # rpc result ('R')
         | 
| 29 | 
            +
                    parse_bytes(bytes)
         | 
| 30 | 
            +
                  else
         | 
| 31 | 
            +
                    raise data
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
             | 
| 36 | 
            +
                def parse(data, klass = nil, options = {})
         | 
| 37 | 
            +
                  parse_bytes(data.each_byte, klass, options)
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
             | 
| 41 | 
            +
                def parse_bytes(bytes, klass = nil, options = {}, refs = [], cdefs = [])
         | 
| 42 | 
            +
                  bc = bytes.next
         | 
| 43 | 
            +
                  case bc
         | 
| 44 | 
            +
                  when 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
         | 
| 45 | 
            +
                       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
         | 
| 46 | 
            +
                       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
         | 
| 47 | 
            +
                       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
         | 
| 48 | 
            +
                    # 0x00 - 0x1f utf-8 string length 0-31
         | 
| 49 | 
            +
                    read_string_direct(bytes, bc)
         | 
| 50 | 
            +
                  when 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
         | 
| 51 | 
            +
                       0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f
         | 
| 52 | 
            +
                    # 0x20 - 0x2f binary data length 0-15
         | 
| 53 | 
            +
                    read_binary_direct(bytes, bc)
         | 
| 54 | 
            +
                  when 0x30, 0x31, 0x32, 0x33
         | 
| 55 | 
            +
                    # 0x30 - 0x33 utf-8 string length 0-1023
         | 
| 56 | 
            +
                    read_string_short(bytes, bc)
         | 
| 57 | 
            +
                  when 0x34, 0x35, 0x36, 0x37
         | 
| 58 | 
            +
                    # 0x34 - 0x37 binary data length 0-1023
         | 
| 59 | 
            +
                    read_binary_short(bytes, bc)
         | 
| 60 | 
            +
                  when 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
         | 
| 61 | 
            +
                    # 0x38 - 0x3f three-octet compact long (-x40000 to x3ffff)
         | 
| 62 | 
            +
                    read_long_short_zero(bytes, bc)
         | 
| 63 | 
            +
                  when 0x41 # 8-bit binary data non-final chunk ('A')
         | 
| 64 | 
            +
                    read_binary_chunk(bytes)
         | 
| 65 | 
            +
                  when 0x42 # 8-bit binary data final chunk ('B')
         | 
| 66 | 
            +
                    read_binary(bytes)
         | 
| 67 | 
            +
                  when 0x43 # object type definition ('C')
         | 
| 68 | 
            +
                    name = parse_string(bytes)
         | 
| 69 | 
            +
                    fields = []
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                    parse_int(bytes).times do
         | 
| 72 | 
            +
                      fields << parse_string(bytes)
         | 
| 73 | 
            +
                    end
         | 
| 74 | 
            +
                    cdefs << Struct.new(*fields.map{|f| f.to_sym})
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                    parse_bytes(bytes, klass, options, refs, cdefs)
         | 
| 77 | 
            +
                  when 0x44 # 64-bit IEEE encoded double ('D')
         | 
| 78 | 
            +
                    read_double(bytes)
         | 
| 79 | 
            +
                  when 0x46 # boolean false ('F')
         | 
| 80 | 
            +
                    false
         | 
| 81 | 
            +
                  when 0x48 # untyped map ('H')
         | 
| 82 | 
            +
                    read_hash(bytes, klass, options, refs, cdefs)
         | 
| 83 | 
            +
                  when 0x49 # 32-bit signed integer ('I')
         | 
| 84 | 
            +
                    read_int(bytes)
         | 
| 85 | 
            +
                  when 0x4a # 64-bit UTC millisecond date
         | 
| 86 | 
            +
                    read_date(bytes)
         | 
| 87 | 
            +
                  when 0x4b # 32-bit UTC minute date
         | 
| 88 | 
            +
                    read_date_minute(bytes)
         | 
| 89 | 
            +
                  when 0x4c # 64-bit signed long integer ('L')
         | 
| 90 | 
            +
                    read_long(bytes)
         | 
| 91 | 
            +
                  when 0x4d # map with type ('M')
         | 
| 92 | 
            +
                    parse_type(bytes)
         | 
| 93 | 
            +
                    read_hash(bytes, klass, options, refs, cdefs)
         | 
| 94 | 
            +
                  when 0x4e # null ('N')
         | 
| 95 | 
            +
                    nil
         | 
| 96 | 
            +
                  when 0x4f # object instance ('O')
         | 
| 97 | 
            +
                    cdef = cdefs[parse_int(bytes)]
         | 
| 98 | 
            +
                    val = cdef.new
         | 
| 99 | 
            +
                    refs << val # store a value reference first
         | 
| 100 | 
            +
                    val.members.each do |sym|
         | 
| 101 | 
            +
                      val[sym] = parse_bytes(bytes, klass, options, refs, cdefs)
         | 
| 102 | 
            +
                    end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                    val
         | 
| 105 | 
            +
                  when 0x51 # reference to map/list/object - integer ('Q')
         | 
| 106 | 
            +
                    refs[parse_int(bytes)]
         | 
| 107 | 
            +
                  when 0x52 # utf-8 string non-final chunk ('R')
         | 
| 108 | 
            +
                    read_string_chunk(bytes)
         | 
| 109 | 
            +
                  when 0x53 # utf-8 string final chunk ('S')
         | 
| 110 | 
            +
                    read_string(bytes)
         | 
| 111 | 
            +
                  when 0x54 # boolean true ('T')
         | 
| 112 | 
            +
                    true
         | 
| 113 | 
            +
                  when 0x55 # variable-length list/vector ('U')
         | 
| 114 | 
            +
                    parse_type(bytes)
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                    is_struct, klass = read_klass(klass)
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                    if is_struct
         | 
| 119 | 
            +
                      arr = []
         | 
| 120 | 
            +
                      while bytes.peek != BC_END
         | 
| 121 | 
            +
                        arr << parse_bytes(bytes, nil, options, refs, cdefs)
         | 
| 122 | 
            +
                      end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                      val = klass.new(*arr)
         | 
| 125 | 
            +
                      refs << val
         | 
| 126 | 
            +
                    else
         | 
| 127 | 
            +
                      val = []
         | 
| 128 | 
            +
                      refs << val # store a value reference first
         | 
| 129 | 
            +
                      while bytes.peek != BC_END
         | 
| 130 | 
            +
                        val << parse_bytes(bytes, klass, options, refs, cdefs)
         | 
| 131 | 
            +
                      end
         | 
| 132 | 
            +
                    end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                    bytes.next
         | 
| 135 | 
            +
                    val
         | 
| 136 | 
            +
                  when 0x56 # fixed-length list/vector ('V')
         | 
| 137 | 
            +
                    parse_type(bytes)
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                    is_struct, klass = read_klass(klass)
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                    if is_struct
         | 
| 142 | 
            +
                      arr = []
         | 
| 143 | 
            +
                      parse_int(bytes).times do
         | 
| 144 | 
            +
                        arr << parse_bytes(bytes, nil, options, refs, cdefs)
         | 
| 145 | 
            +
                      end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                      val = klass.new(*arr)
         | 
| 148 | 
            +
                      refs << val
         | 
| 149 | 
            +
                    else
         | 
| 150 | 
            +
                      val = []
         | 
| 151 | 
            +
                      refs << val # store a value reference
         | 
| 152 | 
            +
                      parse_int(bytes).times do
         | 
| 153 | 
            +
                        val << parse_bytes(bytes, klass, options, refs, cdefs)
         | 
| 154 | 
            +
                      end
         | 
| 155 | 
            +
                    end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                    val
         | 
| 158 | 
            +
                  when 0x57 # variable-length untyped list/vector ('W')
         | 
| 159 | 
            +
                    is_struct, klass = read_klass(klass)
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                    if is_struct
         | 
| 162 | 
            +
                      arr = []
         | 
| 163 | 
            +
                      while bytes.peek != BC_END
         | 
| 164 | 
            +
                        arr << parse_bytes(bytes, nil, options, refs, cdefs)
         | 
| 165 | 
            +
                      end
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                      val = klass.new(*arr)
         | 
| 168 | 
            +
                      refs << val
         | 
| 169 | 
            +
                    else
         | 
| 170 | 
            +
                      val = []
         | 
| 171 | 
            +
                      refs << val # store a value reference first
         | 
| 172 | 
            +
                      while bytes.peek != BC_END
         | 
| 173 | 
            +
                        val << parse_bytes(bytes, klass, options, refs, cdefs)
         | 
| 174 | 
            +
                      end
         | 
| 175 | 
            +
                    end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                    bytes.next
         | 
| 178 | 
            +
                    val
         | 
| 179 | 
            +
                  when 0x58 # fixed-length untyped list/vector ('X')
         | 
| 180 | 
            +
                    is_struct, klass = read_klass(klass)
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                    if is_struct
         | 
| 183 | 
            +
                      arr = []
         | 
| 184 | 
            +
                      parse_int(bytes).times do
         | 
| 185 | 
            +
                        arr << parse_bytes(bytes, nil, options, refs, cdefs)
         | 
| 186 | 
            +
                      end
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                      val = klass.new(*arr)
         | 
| 189 | 
            +
                      refs << val
         | 
| 190 | 
            +
                    else
         | 
| 191 | 
            +
                      val = []
         | 
| 192 | 
            +
                      refs << val # store a value reference first
         | 
| 193 | 
            +
                      parse_int(bytes).times do
         | 
| 194 | 
            +
                        val << parse_bytes(bytes, klass, options, refs, cdefs)
         | 
| 195 | 
            +
                      end
         | 
| 196 | 
            +
                    end
         | 
| 197 | 
            +
             | 
| 198 | 
            +
                    val
         | 
| 199 | 
            +
                  when 0x59 # long encoded as 32-bit int ('Y')
         | 
| 200 | 
            +
                    read_int(bytes)
         | 
| 201 | 
            +
                  when 0x5b # double 0.0
         | 
| 202 | 
            +
                    0
         | 
| 203 | 
            +
                  when 0x5c # double 1.0
         | 
| 204 | 
            +
                    1
         | 
| 205 | 
            +
                  when 0x5d # double represented as byte (-128.0 to 127.0)
         | 
| 206 | 
            +
                    read_double_direct(bytes)
         | 
| 207 | 
            +
                  when 0x5e # double represented as short (-32768.0 to 32767.0)
         | 
| 208 | 
            +
                    read_double_short(bytes)
         | 
| 209 | 
            +
                  when 0x5f # double represented as float
         | 
| 210 | 
            +
                    read_double_mill(bytes)
         | 
| 211 | 
            +
                  when 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
         | 
| 212 | 
            +
                       0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f
         | 
| 213 | 
            +
                    # 0x60 - 0x6f object with direct type
         | 
| 214 | 
            +
                    cdef = cdefs[bc - BC_OBJECT_DIRECT]
         | 
| 215 | 
            +
                    val = cdef.new
         | 
| 216 | 
            +
                    refs << val # store a value reference first
         | 
| 217 | 
            +
                    val.members.each do |sym|
         | 
| 218 | 
            +
                      val[sym] = parse_bytes(bytes, klass, options, refs, cdefs)
         | 
| 219 | 
            +
                    end
         | 
| 220 | 
            +
             | 
| 221 | 
            +
                    val
         | 
| 222 | 
            +
                  when 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77
         | 
| 223 | 
            +
                    # 0x70 - 0x77 fixed list with direct length
         | 
| 224 | 
            +
                    parse_type(bytes)
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                    is_struct, klass = read_klass(klass)
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                    if is_struct
         | 
| 229 | 
            +
                      arr = []
         | 
| 230 | 
            +
                      (bc - BC_LIST_DIRECT).times do
         | 
| 231 | 
            +
                        arr << parse_bytes(bytes, nil, options, refs, cdefs)
         | 
| 232 | 
            +
                      end
         | 
| 233 | 
            +
             | 
| 234 | 
            +
                      val = klass.new(*arr)
         | 
| 235 | 
            +
                      refs << val
         | 
| 236 | 
            +
                    else
         | 
| 237 | 
            +
                      val = []
         | 
| 238 | 
            +
                      refs << val # store a value reference first
         | 
| 239 | 
            +
                      (bc - BC_LIST_DIRECT).times do
         | 
| 240 | 
            +
                        val << parse_bytes(bytes, klass, options, refs, cdefs)
         | 
| 241 | 
            +
                      end
         | 
| 242 | 
            +
                    end
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                    val
         | 
| 245 | 
            +
                  when 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
         | 
| 246 | 
            +
                    # 0x78 - 0x7f fixed untyped list with direct length
         | 
| 247 | 
            +
                    is_struct, klass = read_klass(klass)
         | 
| 248 | 
            +
             | 
| 249 | 
            +
                    if is_struct
         | 
| 250 | 
            +
                      arr = []
         | 
| 251 | 
            +
                      (bc - BC_LIST_DIRECT_UNTYPED).times do
         | 
| 252 | 
            +
                        arr << parse_bytes(bytes, nil, options, refs, cdefs)
         | 
| 253 | 
            +
                      end
         | 
| 254 | 
            +
             | 
| 255 | 
            +
                      val = klass.new(*arr)
         | 
| 256 | 
            +
                      refs << val
         | 
| 257 | 
            +
                    else
         | 
| 258 | 
            +
                      val = []
         | 
| 259 | 
            +
                      refs << val # store a value reference first
         | 
| 260 | 
            +
                      (bc - BC_LIST_DIRECT_UNTYPED).times do
         | 
| 261 | 
            +
                        val << parse_bytes(bytes, klass, options, refs, cdefs)
         | 
| 262 | 
            +
                      end
         | 
| 263 | 
            +
                    end
         | 
| 264 | 
            +
             | 
| 265 | 
            +
                    val
         | 
| 266 | 
            +
                  when 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
         | 
| 267 | 
            +
                       0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
         | 
| 268 | 
            +
                       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
         | 
| 269 | 
            +
                       0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
         | 
| 270 | 
            +
                       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
         | 
| 271 | 
            +
                       0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
         | 
| 272 | 
            +
                       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
         | 
| 273 | 
            +
                       0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf
         | 
| 274 | 
            +
                    # 0x80 - 0xbf one-octet compact int (-x10 to x2f, x90 is 0)
         | 
| 275 | 
            +
                    read_int_zero(bc)
         | 
| 276 | 
            +
                  when 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
         | 
| 277 | 
            +
                       0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf
         | 
| 278 | 
            +
                    # 0xc0 - 0xcf two-octet compact int (-x800 to x7ff)
         | 
| 279 | 
            +
                    read_int_byte_zero(bytes, bc)
         | 
| 280 | 
            +
                  when 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7
         | 
| 281 | 
            +
                    # 0xd0 - 0xd7 three-octet compact int (-x40000 to x3ffff)
         | 
| 282 | 
            +
                    read_int_short_zero(bytes, bc)
         | 
| 283 | 
            +
                  when 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
         | 
| 284 | 
            +
                       0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
         | 
| 285 | 
            +
                       0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef
         | 
| 286 | 
            +
                    # 0xd8 - 0xef one-octet compact long (-x8 to xf, xe0 is 0)
         | 
| 287 | 
            +
                    read_long_zero(bc)
         | 
| 288 | 
            +
                  when 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
         | 
| 289 | 
            +
                       0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
         | 
| 290 | 
            +
                    # 0xf0 - 0xff two-octet compact long (-x800 to x7ff, xf8 is 0)
         | 
| 291 | 
            +
                    read_long_byte_zero(bytes, bc)
         | 
| 292 | 
            +
                  else
         | 
| 293 | 
            +
                    raise sprintf("Invalid type: %#x", bc)
         | 
| 294 | 
            +
                  end
         | 
| 295 | 
            +
                end
         | 
| 296 | 
            +
             | 
| 297 | 
            +
             | 
| 298 | 
            +
                def parse_utf8_char(bytes)
         | 
| 299 | 
            +
                  bc = bytes.next
         | 
| 300 | 
            +
                  if bc < 0x80 # 0xxxxxxx
         | 
| 301 | 
            +
                    bc
         | 
| 302 | 
            +
                  elsif bc & 0xe0 == 0xc0 # 110xxxxx 10xxxxxx
         | 
| 303 | 
            +
                    (bc & 0x1f) * 64 + (bytes.next & 0x3f)
         | 
| 304 | 
            +
                  elsif bc & 0xf0 == 0xe0 # 1110xxxx 10xxxxxx 10xxxxxx
         | 
| 305 | 
            +
                    (bc & 0x0f) * 4096 + (bytes.next & 0x3f) * 64 + (bytes.next & 0x3f)
         | 
| 306 | 
            +
                  else
         | 
| 307 | 
            +
                    raise sprintf("bad utf-8 encoding at %#x", bc)
         | 
| 308 | 
            +
                  end
         | 
| 309 | 
            +
                end
         | 
| 310 | 
            +
             | 
| 311 | 
            +
             | 
| 312 | 
            +
                def parse_binary(bytes)
         | 
| 313 | 
            +
                  bc = bytes.next
         | 
| 314 | 
            +
                  case bc
         | 
| 315 | 
            +
                  when 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
         | 
| 316 | 
            +
                       0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f
         | 
| 317 | 
            +
                    read_binary_direct(bytes, bc)
         | 
| 318 | 
            +
                  when 0x34, 0x35, 0x36, 0x37
         | 
| 319 | 
            +
                    read_binary_short(bytes, bc)
         | 
| 320 | 
            +
                  when 0x41
         | 
| 321 | 
            +
                    read_binary_chunk(bytes)
         | 
| 322 | 
            +
                  when 0x42
         | 
| 323 | 
            +
                    read_binary(bytes)
         | 
| 324 | 
            +
                  else
         | 
| 325 | 
            +
                    raise sprintf("%#x is not a binary", bc)
         | 
| 326 | 
            +
                  end
         | 
| 327 | 
            +
                end
         | 
| 328 | 
            +
             | 
| 329 | 
            +
             | 
| 330 | 
            +
                def parse_int(bytes)
         | 
| 331 | 
            +
                  bc = bytes.next
         | 
| 332 | 
            +
                  case bc
         | 
| 333 | 
            +
                  when 0x49
         | 
| 334 | 
            +
                    read_int(bytes)
         | 
| 335 | 
            +
                  when 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
         | 
| 336 | 
            +
                       0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
         | 
| 337 | 
            +
                       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
         | 
| 338 | 
            +
                       0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
         | 
| 339 | 
            +
                       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
         | 
| 340 | 
            +
                       0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
         | 
| 341 | 
            +
                       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
         | 
| 342 | 
            +
                       0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf
         | 
| 343 | 
            +
                    read_int_zero(bc)
         | 
| 344 | 
            +
                  when 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
         | 
| 345 | 
            +
                       0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf
         | 
| 346 | 
            +
                    read_int_byte_zero(bytes, bc)
         | 
| 347 | 
            +
                  when 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7
         | 
| 348 | 
            +
                    read_int_short_zero(bytes, bc)
         | 
| 349 | 
            +
                  else
         | 
| 350 | 
            +
                    raise sprintf("%#x is not a int", bc)
         | 
| 351 | 
            +
                  end
         | 
| 352 | 
            +
                end
         | 
| 353 | 
            +
             | 
| 354 | 
            +
             | 
| 355 | 
            +
                def parse_string(bytes)
         | 
| 356 | 
            +
                  bc = bytes.next
         | 
| 357 | 
            +
                  case bc
         | 
| 358 | 
            +
                  when 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
         | 
| 359 | 
            +
                       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
         | 
| 360 | 
            +
                       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
         | 
| 361 | 
            +
                       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
         | 
| 362 | 
            +
                    read_string_direct(bytes, bc)
         | 
| 363 | 
            +
                  when 0x30, 0x31, 0x32, 0x33
         | 
| 364 | 
            +
                    read_string_short(bytes, bc)
         | 
| 365 | 
            +
                  when 0x52
         | 
| 366 | 
            +
                    read_string_chunk(bytes)
         | 
| 367 | 
            +
                  when 0x53
         | 
| 368 | 
            +
                    read_string(bytes)
         | 
| 369 | 
            +
                  else
         | 
| 370 | 
            +
                    raise sprintf("%#x is not a string", bc)
         | 
| 371 | 
            +
                  end
         | 
| 372 | 
            +
                end
         | 
| 373 | 
            +
             | 
| 374 | 
            +
             | 
| 375 | 
            +
                def parse_type(bytes)
         | 
| 376 | 
            +
                  bc = bytes.next
         | 
| 377 | 
            +
                  case bc
         | 
| 378 | 
            +
                  when 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
         | 
| 379 | 
            +
                       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
         | 
| 380 | 
            +
                       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
         | 
| 381 | 
            +
                       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
         | 
| 382 | 
            +
                    read_string_direct(bytes, bc)
         | 
| 383 | 
            +
                  when 0x30, 0x31, 0x32, 0x33
         | 
| 384 | 
            +
                    read_string_short(bytes, bc)
         | 
| 385 | 
            +
                  when 0x49
         | 
| 386 | 
            +
                    read_int(bytes)
         | 
| 387 | 
            +
                  when 0x52
         | 
| 388 | 
            +
                    read_string_chunk(bytes)
         | 
| 389 | 
            +
                  when 0x53
         | 
| 390 | 
            +
                    read_string(bytes)
         | 
| 391 | 
            +
                  when 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
         | 
| 392 | 
            +
                       0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
         | 
| 393 | 
            +
                       0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
         | 
| 394 | 
            +
                       0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
         | 
| 395 | 
            +
                       0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
         | 
| 396 | 
            +
                       0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
         | 
| 397 | 
            +
                       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
         | 
| 398 | 
            +
                       0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf
         | 
| 399 | 
            +
                    read_int_zero(bc)
         | 
| 400 | 
            +
                  when 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
         | 
| 401 | 
            +
                       0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf
         | 
| 402 | 
            +
                    read_int_byte_zero(bytes, bc)
         | 
| 403 | 
            +
                  when 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7
         | 
| 404 | 
            +
                    read_int_short_zero(bytes, bc)
         | 
| 405 | 
            +
                  else
         | 
| 406 | 
            +
                    raise sprintf("%#x is not a type", bc)
         | 
| 407 | 
            +
                  end
         | 
| 408 | 
            +
                end
         | 
| 409 | 
            +
             | 
| 410 | 
            +
             | 
| 411 | 
            +
                private
         | 
| 412 | 
            +
             | 
| 413 | 
            +
                def read_binary_direct(bytes, bc)
         | 
| 414 | 
            +
                  read_binary_string(bytes, bc - BC_BINARY_DIRECT)
         | 
| 415 | 
            +
                end
         | 
| 416 | 
            +
             | 
| 417 | 
            +
             | 
| 418 | 
            +
                def read_binary_short(bytes, bc)
         | 
| 419 | 
            +
                  read_binary_string(bytes, ((bc - BC_BINARY_SHORT) << 8) + bytes.next)
         | 
| 420 | 
            +
                end
         | 
| 421 | 
            +
             | 
| 422 | 
            +
             | 
| 423 | 
            +
                def read_binary_chunk(bytes)
         | 
| 424 | 
            +
                  chunks = []
         | 
| 425 | 
            +
                  chunks << read_binary(bytes)
         | 
| 426 | 
            +
                  while(bytes.peek == BC_BINARY_CHUNK)
         | 
| 427 | 
            +
                    bytes.next
         | 
| 428 | 
            +
                    chunks << read_binary(bytes)
         | 
| 429 | 
            +
                  end
         | 
| 430 | 
            +
             | 
| 431 | 
            +
                  chunks << parse_binary(bytes)
         | 
| 432 | 
            +
                  chunks.join
         | 
| 433 | 
            +
                end
         | 
| 434 | 
            +
             | 
| 435 | 
            +
             | 
| 436 | 
            +
                def read_binary(bytes)
         | 
| 437 | 
            +
                  read_binary_string(bytes, bytes.next * 256 + bytes.next)
         | 
| 438 | 
            +
                end
         | 
| 439 | 
            +
             | 
| 440 | 
            +
             | 
| 441 | 
            +
                def read_binary_string(bytes, len)
         | 
| 442 | 
            +
                  [].tap do |arr|
         | 
| 443 | 
            +
                    len.times{ arr << bytes.next } 
         | 
| 444 | 
            +
                  end.pack('C*')
         | 
| 445 | 
            +
                end
         | 
| 446 | 
            +
             | 
| 447 | 
            +
             | 
| 448 | 
            +
                def read_date(bytes)
         | 
| 449 | 
            +
                  val = read_long(bytes)
         | 
| 450 | 
            +
                  Time.at(val / 1000, val % 1000 * 1000)
         | 
| 451 | 
            +
                end
         | 
| 452 | 
            +
             | 
| 453 | 
            +
             | 
| 454 | 
            +
                def read_date_minute(bytes)
         | 
| 455 | 
            +
                  val = bytes.next * 16777216 + bytes.next * 65536 + bytes.next * 256 + bytes.next
         | 
| 456 | 
            +
                  Time.at(val * 60)
         | 
| 457 | 
            +
                end
         | 
| 458 | 
            +
             | 
| 459 | 
            +
             | 
| 460 | 
            +
                def read_double(bytes)
         | 
| 461 | 
            +
                  # b64, b56, b48, b40, b32, b24, b16, b8 = bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next
         | 
| 462 | 
            +
                  # bits = b64 * 72057594037927936 + b56 * 281474976710656 + b48 * 1099511627776 + b40 * 4294967296 \
         | 
| 463 | 
            +
                  #   + b32 * 16777216 + b24 * 65536 + b16 * 256 + b8
         | 
| 464 | 
            +
                  # return Float::INFINITY if bits == 0x7_ff0_000_000_000_000
         | 
| 465 | 
            +
                  # return -Float::INFINITY if bits == 0xf_ff0_000_000_000_000
         | 
| 466 | 
            +
                  # return Float::NAN if (bits >= 0x7_ff0_000_000_000_001 && bits <= 0x7_fff_fff_fff_fff_fff) or (bits >= 0xf_ff0_000_000_000_001 && bits <= 0xf_fff_fff_fff_fff_fff)
         | 
| 467 | 
            +
                  # s = b64 < 0x80 ? 1 : -1
         | 
| 468 | 
            +
                  # e = (bits / 4503599627370496) & 0x7ff
         | 
| 469 | 
            +
                  # m = (e == 0) ? (bits & 0xf_fff_fff_fff_fff) << 1 : (bits & 0xf_fff_fff_fff_fff) | 0x10_000_000_000_000
         | 
| 470 | 
            +
                  # (s * m * 2**(e - 1075)).to_f # maybe get a rational, so to_f
         | 
| 471 | 
            +
                  [ bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next ].pack('C*').unpack('G').first # faster than s * m * 2**(e - 1075)
         | 
| 472 | 
            +
                end
         | 
| 473 | 
            +
             | 
| 474 | 
            +
             | 
| 475 | 
            +
                def read_double_direct(bytes)
         | 
| 476 | 
            +
                  bc = bytes.next
         | 
| 477 | 
            +
                  bc < 0x80 ? bc : -(0xff - bc + 1)
         | 
| 478 | 
            +
                end
         | 
| 479 | 
            +
             | 
| 480 | 
            +
             | 
| 481 | 
            +
                def read_double_short(bytes)
         | 
| 482 | 
            +
                  b16, b8 = bytes.next, bytes.next
         | 
| 483 | 
            +
                  if b16 < 0x80
         | 
| 484 | 
            +
                    b16 * 256 + b8
         | 
| 485 | 
            +
                  else
         | 
| 486 | 
            +
                    -((0xff - b16) * 256 + 0xff - b8 + 1)
         | 
| 487 | 
            +
                  end
         | 
| 488 | 
            +
                end
         | 
| 489 | 
            +
             | 
| 490 | 
            +
             | 
| 491 | 
            +
                def read_double_mill(bytes)
         | 
| 492 | 
            +
                  0.001 * read_int(bytes)
         | 
| 493 | 
            +
                end
         | 
| 494 | 
            +
             | 
| 495 | 
            +
             | 
| 496 | 
            +
                def read_hash(bytes, klass, options, refs, cdefs)
         | 
| 497 | 
            +
                  val = {}
         | 
| 498 | 
            +
                  refs << val
         | 
| 499 | 
            +
                  if options[:symbolize_keys]
         | 
| 500 | 
            +
                    val[parse_bytes(bytes, klass, options, refs, cdefs).to_sym] = parse_bytes(bytes, klass, options, refs, cdefs) while bytes.peek != BC_END
         | 
| 501 | 
            +
                  else
         | 
| 502 | 
            +
                    val[parse_bytes(bytes, klass, options, refs, cdefs)] = parse_bytes(bytes, klass, options, refs, cdefs) while bytes.peek != BC_END
         | 
| 503 | 
            +
                  end
         | 
| 504 | 
            +
                  bytes.next
         | 
| 505 | 
            +
             | 
| 506 | 
            +
                  val
         | 
| 507 | 
            +
                end
         | 
| 508 | 
            +
             | 
| 509 | 
            +
             | 
| 510 | 
            +
                def read_int(bytes)
         | 
| 511 | 
            +
                  b32, b24, b16, b8 = bytes.next, bytes.next, bytes.next, bytes.next
         | 
| 512 | 
            +
                  if b32 < 0x80
         | 
| 513 | 
            +
                    b32 * 16777216 + b24 * 65536 + b16 * 256 + b8
         | 
| 514 | 
            +
                  else
         | 
| 515 | 
            +
                    -((0xff - b32) * 16777216 + (0xff - b24) * 65536 + (0xff - b16) * 256 + 0xff - b8 + 1)
         | 
| 516 | 
            +
                  end
         | 
| 517 | 
            +
                end
         | 
| 518 | 
            +
             | 
| 519 | 
            +
             | 
| 520 | 
            +
                def read_int_zero(bc)
         | 
| 521 | 
            +
                  bc - BC_INT_ZERO
         | 
| 522 | 
            +
                end
         | 
| 523 | 
            +
             | 
| 524 | 
            +
             | 
| 525 | 
            +
                def read_int_byte_zero(bytes, bc)
         | 
| 526 | 
            +
                  (bc - BC_INT_BYTE_ZERO) * 256 + bytes.next
         | 
| 527 | 
            +
                end
         | 
| 528 | 
            +
             | 
| 529 | 
            +
             | 
| 530 | 
            +
                def read_int_short_zero(bytes, bc)
         | 
| 531 | 
            +
                  (bc - BC_INT_SHORT_ZERO) * 65536 + bytes.next * 256 + bytes.next
         | 
| 532 | 
            +
                end
         | 
| 533 | 
            +
             | 
| 534 | 
            +
             | 
| 535 | 
            +
                def read_klass(klass)
         | 
| 536 | 
            +
                  if klass.nil?
         | 
| 537 | 
            +
                    is_struct = false
         | 
| 538 | 
            +
                  elsif klass.is_a?(Array)
         | 
| 539 | 
            +
                    is_struct = false
         | 
| 540 | 
            +
                    klass = klass.first
         | 
| 541 | 
            +
                  elsif klass.is_a?(String)
         | 
| 542 | 
            +
                    if klass.include?('[')
         | 
| 543 | 
            +
                      is_struct = false
         | 
| 544 | 
            +
                      klass = Kernel.const_get(klass.delete('[]'))
         | 
| 545 | 
            +
                    else
         | 
| 546 | 
            +
                      is_struct = true
         | 
| 547 | 
            +
                      klass = Kernel.const_get(klass)
         | 
| 548 | 
            +
                    end
         | 
| 549 | 
            +
                  else
         | 
| 550 | 
            +
                    is_struct = true
         | 
| 551 | 
            +
                  end
         | 
| 552 | 
            +
             | 
| 553 | 
            +
                  [ is_struct, klass ]
         | 
| 554 | 
            +
                end
         | 
| 555 | 
            +
             | 
| 556 | 
            +
             | 
| 557 | 
            +
                def read_long(bytes)
         | 
| 558 | 
            +
                  b64, b56, b48, b40, b32, b24, b16, b8 = bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next
         | 
| 559 | 
            +
                  if b64 < 0x80
         | 
| 560 | 
            +
                    b64 * 72057594037927936 + b56 * 281474976710656 + b48 * 1099511627776 + b40 * 4294967296 \
         | 
| 561 | 
            +
                      + b32 * 16777216 + b24 * 65536 + b16 * 256 + b8
         | 
| 562 | 
            +
                  else
         | 
| 563 | 
            +
                    -((0xff - b64) * 72057594037927936 + (0xff - b56) * 281474976710656 + (0xff - b48) * 1099511627776 + (0xff - b40) * 4294967296 \
         | 
| 564 | 
            +
                      + (0xff - b32) * 16777216 + (0xff - b24) * 65536 + (0xff - b16) * 256 + 0xff - b8 + 1)
         | 
| 565 | 
            +
                  end
         | 
| 566 | 
            +
                end
         | 
| 567 | 
            +
             | 
| 568 | 
            +
             | 
| 569 | 
            +
                def read_long_zero(bc)
         | 
| 570 | 
            +
                  bc - BC_LONG_ZERO
         | 
| 571 | 
            +
                end
         | 
| 572 | 
            +
             | 
| 573 | 
            +
             | 
| 574 | 
            +
                def read_long_byte_zero(bytes, bc)
         | 
| 575 | 
            +
                  (bc - BC_LONG_BYTE_ZERO) * 256 + bytes.next
         | 
| 576 | 
            +
                end
         | 
| 577 | 
            +
             | 
| 578 | 
            +
             | 
| 579 | 
            +
                def read_long_short_zero(bytes, bc)
         | 
| 580 | 
            +
                  (bc - BC_LONG_SHORT_ZERO) * 65536 + bytes.next * 256 + bytes.next
         | 
| 581 | 
            +
                end
         | 
| 582 | 
            +
             | 
| 583 | 
            +
             | 
| 584 | 
            +
                def read_string_direct(bytes, bc)
         | 
| 585 | 
            +
                  read_utf8_string(bytes, bc - BC_STRING_DIRECT)
         | 
| 586 | 
            +
                end
         | 
| 587 | 
            +
             | 
| 588 | 
            +
             | 
| 589 | 
            +
                def read_string_short(bytes, bc)
         | 
| 590 | 
            +
                  read_utf8_string(bytes, (bc - BC_STRING_SHORT) * 256 + bytes.next)
         | 
| 591 | 
            +
                end
         | 
| 592 | 
            +
             | 
| 593 | 
            +
             | 
| 594 | 
            +
                def read_string_chunk(bytes)
         | 
| 595 | 
            +
                  chunks = []
         | 
| 596 | 
            +
                  chunks << read_string(bytes)
         | 
| 597 | 
            +
                  while(bytes.peek == BC_STRING_CHUNK)
         | 
| 598 | 
            +
                    bytes.next
         | 
| 599 | 
            +
                    chunks << read_string(bytes)
         | 
| 600 | 
            +
                  end
         | 
| 601 | 
            +
                  
         | 
| 602 | 
            +
                  chunks << parse_string(bytes)
         | 
| 603 | 
            +
                  chunks.join
         | 
| 604 | 
            +
                end
         | 
| 605 | 
            +
             | 
| 606 | 
            +
             | 
| 607 | 
            +
                def read_string(bytes)
         | 
| 608 | 
            +
                  read_utf8_string(bytes, bytes.next * 256 + bytes.next)
         | 
| 609 | 
            +
                end
         | 
| 610 | 
            +
             | 
| 611 | 
            +
             | 
| 612 | 
            +
                def read_utf8_string(bytes, len)
         | 
| 613 | 
            +
                  [].tap do |chars|
         | 
| 614 | 
            +
                    len.times{ chars << parse_utf8_char(bytes) }
         | 
| 615 | 
            +
                  end.pack('U*')
         | 
| 616 | 
            +
                end
         | 
| 617 | 
            +
             | 
| 618 | 
            +
              end
         | 
| 619 | 
            +
            end
         |