Method: ABI::Decoder#decode
- Defined in:
- lib/abicoder/decoder.rb
#decode(types, data, raise_errors = false) ⇒ Object
Decodes multiple arguments using the head/tail mechanism.
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/abicoder/decoder.rb', line 9 def decode( types, data, raise_errors = false ) ## ## todo/check: always change data (string) to binary encoding (e.g. data = data.b ) ## or such - why? why not? ## for convenience check if types is a String ## otherwise assume ABI::Type already types = types.map { |type| type.is_a?( Type ) ? type : Type.parse( type ) } outputs = [nil] * types.size start_positions = [nil] * types.size + [data.size] # TODO: refactor, a reverse iteration will be better - why? why not? # try to simplify / clean-up code - possible? why? why not? pos = 0 types.each_with_index do |t, i| # If a type is static, grab the data directly, otherwise record its # start position if t.dynamic? if pos>data.size-1 if raise_errors raise DecodingError, "Position out of bounds #{pos}>#{data.size-1}" else puts "!! WARN - DecodingError: Position out of bounds #{pos}>#{data.size-1}" end end start_positions[i] = decode_uint256(data[pos, 32]) if start_positions[i]>data.size-1 if raise_errors raise DecodingError, "Start position out of bounds #{start_positions[i]}>#{data.size-1}" else puts "!! WARN - DecodingError: Start position out of bounds #{start_positions[i]}>#{data.size-1}" end end j = i - 1 while j >= 0 && start_positions[j].nil? start_positions[j] = start_positions[i] j -= 1 end pos += 32 else ## puts "step 1 - decode item [#{i}] - #{t.format} size: #{t.size} dynamic? #{t.dynamic?}" count = t.size ## was zero_padding( data, pos, t.size, start_positions ) ## inline for now and clean-up later - why? why not? outputs[i] = if pos >= data.size start_positions[start_positions.size-1] += count BYTE_ZERO*count elsif pos + count > data.size start_positions[start_positions.size-1] += ( count - (data.size-pos)) data[pos,data.size-pos] + BYTE_ZERO*( count - (data.size-pos)) else data[pos, count] end pos += t.size end end # We add a start position equal to the length of the entire data for # convenience. j = types.size - 1 while j >= 0 && start_positions[j].nil? start_positions[j] = start_positions[types.size] j -= 1 end if pos > data.size if raise_errors raise DecodingError, "Not enough data for head" else puts "!! WARN - DecodingError: Not enough data for head" end end types.each_with_index do |t, i| if t.dynamic? offset, next_offset = start_positions[i, 2] if offset<=data.size && next_offset<=data.size outputs[i] = data[offset...next_offset] end end end if outputs.include?( nil ) if raise_errors raise DecodingError, "Not all data can be parsed" else puts "!! WARN: DecodingError - Not all data can be parsed" end end types.zip(outputs).map do |(t, out)| ## puts "step 2 - decode item - #{t.format} got: #{out.size} byte(s) - size: #{t.size} dynamic? #{t.dynamic?}" decode_type(t, out) end end |