module Hessian2::Parser
Public Instance Methods
parse(data, klass = nil, options = {})
click to toggle source
# File lib/hessian2/parser.rb, line 36 def parse(data, klass = nil, options = {}) parse_bytes(data.each_byte, klass, options) end
parse_binary(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 312 def parse_binary(bytes) bc = bytes.next case bc when 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f read_binary_direct(bytes, bc) when 0x34, 0x35, 0x36, 0x37 read_binary_short(bytes, bc) when 0x41 read_binary_chunk(bytes) when 0x42 read_binary(bytes) else raise sprintf("%#x is not a binary", bc) end end
parse_bytes(bytes, klass = nil, options = {}, refs = [], cdefs = [])
click to toggle source
# File lib/hessian2/parser.rb, line 41 def parse_bytes(bytes, klass = nil, options = {}, refs = [], cdefs = []) bc = bytes.next case bc when 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f # 0x00 - 0x1f utf-8 string length 0-31 read_string_direct(bytes, bc) when 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f # 0x20 - 0x2f binary data length 0-15 read_binary_direct(bytes, bc) when 0x30, 0x31, 0x32, 0x33 # 0x30 - 0x33 utf-8 string length 0-1023 read_string_short(bytes, bc) when 0x34, 0x35, 0x36, 0x37 # 0x34 - 0x37 binary data length 0-1023 read_binary_short(bytes, bc) when 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f # 0x38 - 0x3f three-octet compact long (-x40000 to x3ffff) read_long_short_zero(bytes, bc) when 0x41 # 8-bit binary data non-final chunk ('A') read_binary_chunk(bytes) when 0x42 # 8-bit binary data final chunk ('B') read_binary(bytes) when 0x43 # object type definition ('C') name = parse_string(bytes) fields = [] parse_int(bytes).times do fields << parse_string(bytes) end cdefs << Struct.new(*fields.map{|f| f.to_sym}) parse_bytes(bytes, klass, options, refs, cdefs) when 0x44 # 64-bit IEEE encoded double ('D') read_double(bytes) when 0x46 # boolean false ('F') false when 0x48 # untyped map ('H') read_hash(bytes, klass, options, refs, cdefs) when 0x49 # 32-bit signed integer ('I') read_int(bytes) when 0x4a # 64-bit UTC millisecond date read_date(bytes) when 0x4b # 32-bit UTC minute date read_date_minute(bytes) when 0x4c # 64-bit signed long integer ('L') read_long(bytes) when 0x4d # map with type ('M') parse_type(bytes) read_hash(bytes, klass, options, refs, cdefs) when 0x4e # null ('N') nil when 0x4f # object instance ('O') cdef = cdefs[parse_int(bytes)] val = cdef.new refs << val # store a value reference first val.members.each do |sym| val[sym] = parse_bytes(bytes, klass, options, refs, cdefs) end val when 0x51 # reference to map/list/object - integer ('Q') refs[parse_int(bytes)] when 0x52 # utf-8 string non-final chunk ('R') read_string_chunk(bytes) when 0x53 # utf-8 string final chunk ('S') read_string(bytes) when 0x54 # boolean true ('T') true when 0x55 # variable-length list/vector ('U') parse_type(bytes) is_struct, klass = read_klass(klass) if is_struct arr = [] while bytes.peek != BC_END arr << parse_bytes(bytes, nil, options, refs, cdefs) end val = klass.new(*arr) refs << val else val = [] refs << val # store a value reference first while bytes.peek != BC_END val << parse_bytes(bytes, klass, options, refs, cdefs) end end bytes.next val when 0x56 # fixed-length list/vector ('V') parse_type(bytes) is_struct, klass = read_klass(klass) if is_struct arr = [] parse_int(bytes).times do arr << parse_bytes(bytes, nil, options, refs, cdefs) end val = klass.new(*arr) refs << val else val = [] refs << val # store a value reference parse_int(bytes).times do val << parse_bytes(bytes, klass, options, refs, cdefs) end end val when 0x57 # variable-length untyped list/vector ('W') is_struct, klass = read_klass(klass) if is_struct arr = [] while bytes.peek != BC_END arr << parse_bytes(bytes, nil, options, refs, cdefs) end val = klass.new(*arr) refs << val else val = [] refs << val # store a value reference first while bytes.peek != BC_END val << parse_bytes(bytes, klass, options, refs, cdefs) end end bytes.next val when 0x58 # fixed-length untyped list/vector ('X') is_struct, klass = read_klass(klass) if is_struct arr = [] parse_int(bytes).times do arr << parse_bytes(bytes, nil, options, refs, cdefs) end val = klass.new(*arr) refs << val else val = [] refs << val # store a value reference first parse_int(bytes).times do val << parse_bytes(bytes, klass, options, refs, cdefs) end end val when 0x59 # long encoded as 32-bit int ('Y') read_int(bytes) when 0x5b # double 0.0 0 when 0x5c # double 1.0 1 when 0x5d # double represented as byte (-128.0 to 127.0) read_double_direct(bytes) when 0x5e # double represented as short (-32768.0 to 32767.0) read_double_short(bytes) when 0x5f # double represented as float read_double_mill(bytes) when 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f # 0x60 - 0x6f object with direct type cdef = cdefs[bc - BC_OBJECT_DIRECT] val = cdef.new refs << val # store a value reference first val.members.each do |sym| val[sym] = parse_bytes(bytes, klass, options, refs, cdefs) end val when 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77 # 0x70 - 0x77 fixed list with direct length parse_type(bytes) is_struct, klass = read_klass(klass) if is_struct arr = [] (bc - BC_LIST_DIRECT).times do arr << parse_bytes(bytes, nil, options, refs, cdefs) end val = klass.new(*arr) refs << val else val = [] refs << val # store a value reference first (bc - BC_LIST_DIRECT).times do val << parse_bytes(bytes, klass, options, refs, cdefs) end end val when 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f # 0x78 - 0x7f fixed untyped list with direct length is_struct, klass = read_klass(klass) if is_struct arr = [] (bc - BC_LIST_DIRECT_UNTYPED).times do arr << parse_bytes(bytes, nil, options, refs, cdefs) end val = klass.new(*arr) refs << val else val = [] refs << val # store a value reference first (bc - BC_LIST_DIRECT_UNTYPED).times do val << parse_bytes(bytes, klass, options, refs, cdefs) end end val when 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf # 0x80 - 0xbf one-octet compact int (-x10 to x2f, x90 is 0) read_int_zero(bc) when 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf # 0xc0 - 0xcf two-octet compact int (-x800 to x7ff) read_int_byte_zero(bytes, bc) when 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7 # 0xd0 - 0xd7 three-octet compact int (-x40000 to x3ffff) read_int_short_zero(bytes, bc) when 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef # 0xd8 - 0xef one-octet compact long (-x8 to xf, xe0 is 0) read_long_zero(bc) when 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff # 0xf0 - 0xff two-octet compact long (-x800 to x7ff, xf8 is 0) read_long_byte_zero(bytes, bc) else raise sprintf("Invalid type: %#x", bc) end end
parse_int(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 330 def parse_int(bytes) bc = bytes.next case bc when 0x49 read_int(bytes) when 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf read_int_zero(bc) when 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf read_int_byte_zero(bytes, bc) when 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7 read_int_short_zero(bytes, bc) else raise sprintf("%#x is not a int", bc) end end
parse_rpc(data)
click to toggle source
# File lib/hessian2/parser.rb, line 8 def parse_rpc(data) bytes = data.each_byte bc = bytes.next if bc == 0x48 # skip hessian version 2.times{ bytes.next } bc = bytes.next end case bc when 0x43 # rpc call ('C') method = parse_string(bytes) refs, cdefs = [], [] args = [].tap do |arr| parse_int(bytes).times{ arr << parse_bytes(bytes, nil, {}, refs, cdefs) } end [ method, *args ] when 0x46 # fault ('F') fault = parse_bytes(bytes) code, message = fault['code'], fault['message'] raise Fault.new, code == 'RuntimeError' ? message : "#{code} - #{message}" when 0x52 # rpc result ('R') parse_bytes(bytes) else raise data end end
parse_string(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 355 def parse_string(bytes) bc = bytes.next case bc when 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f read_string_direct(bytes, bc) when 0x30, 0x31, 0x32, 0x33 read_string_short(bytes, bc) when 0x52 read_string_chunk(bytes) when 0x53 read_string(bytes) else raise sprintf("%#x is not a string", bc) end end
parse_type(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 375 def parse_type(bytes) bc = bytes.next case bc when 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f read_string_direct(bytes, bc) when 0x30, 0x31, 0x32, 0x33 read_string_short(bytes, bc) when 0x49 read_int(bytes) when 0x52 read_string_chunk(bytes) when 0x53 read_string(bytes) when 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf read_int_zero(bc) when 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf read_int_byte_zero(bytes, bc) when 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7 read_int_short_zero(bytes, bc) else raise sprintf("%#x is not a type", bc) end end
parse_utf8_char(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 298 def parse_utf8_char(bytes) bc = bytes.next if bc < 0x80 # 0xxxxxxx bc elsif bc & 0xe0 == 0xc0 # 110xxxxx 10xxxxxx (bc & 0x1f) * 64 + (bytes.next & 0x3f) elsif bc & 0xf0 == 0xe0 # 1110xxxx 10xxxxxx 10xxxxxx (bc & 0x0f) * 4096 + (bytes.next & 0x3f) * 64 + (bytes.next & 0x3f) else raise sprintf("bad utf-8 encoding at %#x", bc) end end
Private Instance Methods
read_binary(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 436 def read_binary(bytes) read_binary_string(bytes, bytes.next * 256 + bytes.next) end
read_binary_chunk(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 423 def read_binary_chunk(bytes) chunks = [] chunks << read_binary(bytes) while(bytes.peek == BC_BINARY_CHUNK) bytes.next chunks << read_binary(bytes) end chunks << parse_binary(bytes) chunks.join end
read_binary_direct(bytes, bc)
click to toggle source
# File lib/hessian2/parser.rb, line 413 def read_binary_direct(bytes, bc) read_binary_string(bytes, bc - BC_BINARY_DIRECT) end
read_binary_short(bytes, bc)
click to toggle source
# File lib/hessian2/parser.rb, line 418 def read_binary_short(bytes, bc) read_binary_string(bytes, ((bc - BC_BINARY_SHORT) << 8) + bytes.next) end
read_binary_string(bytes, len)
click to toggle source
# File lib/hessian2/parser.rb, line 441 def read_binary_string(bytes, len) [].tap do |arr| len.times{ arr << bytes.next } end.pack('C*') end
read_date(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 448 def read_date(bytes) val = read_long(bytes) Time.at(val / 1000, val % 1000 * 1000) end
read_date_minute(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 454 def read_date_minute(bytes) val = bytes.next * 16777216 + bytes.next * 65536 + bytes.next * 256 + bytes.next Time.at(val * 60) end
read_double(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 460 def read_double(bytes) # b64, b56, b48, b40, b32, b24, b16, b8 = bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next # bits = b64 * 72057594037927936 + b56 * 281474976710656 + b48 * 1099511627776 + b40 * 4294967296 \ # + b32 * 16777216 + b24 * 65536 + b16 * 256 + b8 # return Float::INFINITY if bits == 0x7_ff0_000_000_000_000 # return -Float::INFINITY if bits == 0xf_ff0_000_000_000_000 # 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) # s = b64 < 0x80 ? 1 : -1 # e = (bits / 4503599627370496) & 0x7ff # m = (e == 0) ? (bits & 0xf_fff_fff_fff_fff) << 1 : (bits & 0xf_fff_fff_fff_fff) | 0x10_000_000_000_000 # (s * m * 2**(e - 1075)).to_f # maybe get a rational, so to_f [ 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) end
read_double_direct(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 475 def read_double_direct(bytes) bc = bytes.next bc < 0x80 ? bc : -(0xff - bc + 1) end
read_double_mill(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 491 def read_double_mill(bytes) 0.001 * read_int(bytes) end
read_double_short(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 481 def read_double_short(bytes) b16, b8 = bytes.next, bytes.next if b16 < 0x80 b16 * 256 + b8 else -((0xff - b16) * 256 + 0xff - b8 + 1) end end
read_hash(bytes, klass, options, refs, cdefs)
click to toggle source
# File lib/hessian2/parser.rb, line 496 def read_hash(bytes, klass, options, refs, cdefs) val = {} refs << val if options[:symbolize_keys] val[parse_bytes(bytes, klass, options, refs, cdefs).to_sym] = parse_bytes(bytes, klass, options, refs, cdefs) while bytes.peek != BC_END else val[parse_bytes(bytes, klass, options, refs, cdefs)] = parse_bytes(bytes, klass, options, refs, cdefs) while bytes.peek != BC_END end bytes.next val end
read_int(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 510 def read_int(bytes) b32, b24, b16, b8 = bytes.next, bytes.next, bytes.next, bytes.next if b32 < 0x80 b32 * 16777216 + b24 * 65536 + b16 * 256 + b8 else -((0xff - b32) * 16777216 + (0xff - b24) * 65536 + (0xff - b16) * 256 + 0xff - b8 + 1) end end
read_int_byte_zero(bytes, bc)
click to toggle source
# File lib/hessian2/parser.rb, line 525 def read_int_byte_zero(bytes, bc) (bc - BC_INT_BYTE_ZERO) * 256 + bytes.next end
read_int_short_zero(bytes, bc)
click to toggle source
# File lib/hessian2/parser.rb, line 530 def read_int_short_zero(bytes, bc) (bc - BC_INT_SHORT_ZERO) * 65536 + bytes.next * 256 + bytes.next end
read_int_zero(bc)
click to toggle source
# File lib/hessian2/parser.rb, line 520 def read_int_zero(bc) bc - BC_INT_ZERO end
read_klass(klass)
click to toggle source
# File lib/hessian2/parser.rb, line 535 def read_klass(klass) if klass.nil? is_struct = false elsif klass.is_a?(Array) is_struct = false klass = klass.first elsif klass.is_a?(String) if klass.include?('[') is_struct = false klass = Kernel.const_get(klass.delete('[]')) else is_struct = true klass = Kernel.const_get(klass) end else is_struct = true end [ is_struct, klass ] end
read_long(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 557 def read_long(bytes) b64, b56, b48, b40, b32, b24, b16, b8 = bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next, bytes.next if b64 < 0x80 b64 * 72057594037927936 + b56 * 281474976710656 + b48 * 1099511627776 + b40 * 4294967296 \ + b32 * 16777216 + b24 * 65536 + b16 * 256 + b8 else -((0xff - b64) * 72057594037927936 + (0xff - b56) * 281474976710656 + (0xff - b48) * 1099511627776 + (0xff - b40) * 4294967296 \ + (0xff - b32) * 16777216 + (0xff - b24) * 65536 + (0xff - b16) * 256 + 0xff - b8 + 1) end end
read_long_byte_zero(bytes, bc)
click to toggle source
# File lib/hessian2/parser.rb, line 574 def read_long_byte_zero(bytes, bc) (bc - BC_LONG_BYTE_ZERO) * 256 + bytes.next end
read_long_short_zero(bytes, bc)
click to toggle source
# File lib/hessian2/parser.rb, line 579 def read_long_short_zero(bytes, bc) (bc - BC_LONG_SHORT_ZERO) * 65536 + bytes.next * 256 + bytes.next end
read_long_zero(bc)
click to toggle source
# File lib/hessian2/parser.rb, line 569 def read_long_zero(bc) bc - BC_LONG_ZERO end
read_string(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 607 def read_string(bytes) read_utf8_string(bytes, bytes.next * 256 + bytes.next) end
read_string_chunk(bytes)
click to toggle source
# File lib/hessian2/parser.rb, line 594 def read_string_chunk(bytes) chunks = [] chunks << read_string(bytes) while(bytes.peek == BC_STRING_CHUNK) bytes.next chunks << read_string(bytes) end chunks << parse_string(bytes) chunks.join end
read_string_direct(bytes, bc)
click to toggle source
# File lib/hessian2/parser.rb, line 584 def read_string_direct(bytes, bc) read_utf8_string(bytes, bc - BC_STRING_DIRECT) end
read_string_short(bytes, bc)
click to toggle source
# File lib/hessian2/parser.rb, line 589 def read_string_short(bytes, bc) read_utf8_string(bytes, (bc - BC_STRING_SHORT) * 256 + bytes.next) end
read_utf8_string(bytes, len)
click to toggle source
# File lib/hessian2/parser.rb, line 612 def read_utf8_string(bytes, len) [].tap do |chars| len.times{ chars << parse_utf8_char(bytes) } end.pack('U*') end