dmendel / bindata

BinData - Reading and Writing Binary Data in Ruby
BSD 2-Clause "Simplified" License
577 stars 55 forks source link

Mismatch values while doing to_binary_s #60

Closed nazarhussain closed 9 years ago

nazarhussain commented 9 years ago

Hello,

I am building a complex packet architecture to work on a tcp connection. While writing a dummy script to behave like a physical hardware I noticed one thing, which is seems to a strange behavior.

Suppose I have these three Binary Records:

class Alpha < BinData::Record
  int8 :rtc_hour
  int8 :rtc_minute
  int8 :rtc_second
  int8 :rtc_year
  int8 :rtc_month
  int8 :rtc_day
end

class Beta < BinData::Record
  int8 :rtc_hour
  int8 :rtc_minute
  int8 :rtc_second
  int8 :rtc_year
  int8 :rtc_month
  int8 :rtc_day
end

class Base < BinData::Record
  uint16be :transaction_type
  choice :packet_type, :selection => :transaction_type do
    string 1, :value => "Alpha"
    string 2, :value => "Beta"
  end
  choice :packet_content, :selection => :transaction_type do
    alpha 1
    beta 2
  end
end

Now if I execute these lines of code:

packet = Base.new
packet.transaction_type = 1
packet2 = Base.new.read(packet.to_binary_s)

pp packet
pp packet2

I get following output:

{:transaction_type=>1,
 :packet_type=>"Alpha",
 :packet_content=>
  {:rtc_hour=>0,
   :rtc_minute=>0,
   :rtc_second=>0,
   :rtc_year=>0,
   :rtc_month=>0,
   :rtc_day=>0}}
{:transaction_type=>1,
 :packet_type=>"Alpha",
 :packet_content=>
  {:rtc_hour=>65,
   :rtc_minute=>108,
   :rtc_second=>112,
   :rtc_year=>104,
   :rtc_month=>97,
   :rtc_day=>0}}

As you can notice second packet which was built using to_binary_s from the first packet is having garbage values.

Can you please guide me why I am facing this strange behavior.

nazarhussain commented 9 years ago

I just tried another way:

packet = Base.new
packet.transaction_type = 1
io = File.open("test.bin", "w+")
packet.write(io)
packet2 = Base.new.read(io)

Its showing error:

/home/user/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/bindata-2.1.0/lib/bindata/io.rb:82:in `readbytes': End of file reached (EOFError)
    from (eval):23:in `read_and_return_value'
    from /home/user/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/bindata-2.1.0/lib/bindata/base_primitive.rb:124:in `do_read'
    from /home/user/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/bindata-2.1.0/lib/bindata/struct.rb:131:in `block in do_read'
    from /home/user/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/bindata-2.1.0/lib/bindata/struct.rb:131:in `each'
    from /home/user/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/bindata-2.1.0/lib/bindata/struct.rb:131:in `do_read'
    from /home/user/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/bindata-2.1.0/lib/bindata/base.rb:146:in `read'

Please look into this.

dmendel commented 9 years ago

Do you want :packet_type to appear in the data stream? The "garbage" values are the ascii values for A l p h a. If you want to use :packet_type for annotation, use virtual instead of string.

io = File.open("test.bin", "w+")
io.write("foo")
io.read(3)

Yes this won't work. Either close and re-open the file, or call rewind.

nazarhussain commented 9 years ago

@dmendel You are awesome. I wonder how I didn't notice the values and pointed out these were ascii values.

I made 'packet_type' to virtual and resolved the issue.