Reputation: 11
I'm trying to send a very long binary integer over UDP (on the order of 200 bits). When I try to use Array's pack method, it complains the string I'm trying to convert is too large.
Am I going about this the wrong way?
ruby-1.8.7-p352 :003 > [0b1101001010101101111010100101010011010101010110010101010101010010010101001010101010101011101010101010101111010101010101010101].pack('i')
RangeError: bignum too big to convert into `unsigned long'
from (irb):3:in `pack'
from (irb):3
This number is supposed to represent a DNS query packet (this is for a homework assignment; we're not allowed to use any DNS libraries).
Upvotes: 1
Views: 2309
Reputation: 104050
You need to break apart your number into smaller pieces. Probably best is to encode 32 bits at a time:
> num = 0b1101001010101101111010100101010011010101010110010101010101010010010101001010101010101011101010101010101111010101010101010101
=> 17502556204775004286774747314501014869
> low_1 = num & 0xFFFFFFFF
=> 2864534869
> low_2 = (num >> 32) & 0xFFFFFFFF
=> 625650362
> low_3 = (num >> 64) & 0xFFFFFFFF
=> 1297454421
> low_4 = (num >> 96) & 0xFFFFFFFF
=> 220913317
> (low_4 << 96) + (low_3 << 64) + (low_2 << 32) + low_1
=> 17502556204775004286774747314501014869
> msg = [low_4, low_3, low_2, low_1].pack("NNNN")
=> "\r*\336\245MU\225U%J\252\272\252\275UU"
> msg.unpack("NNNN").inject {|sum, elem| (sum << 32) + elem}
=> 17502556204775004286774747314501014869
I prefer 32
bits here because you pack these in Network Byte Order, which makes interopation with other platforms much easier. The pack()
method doesn't provide a network byte order 64-bit integer. (Which isn't too surprising, since POSIX doesn't provide a 64-bit routine.)
Upvotes: 4
Reputation: 3899
Ruby 1.9.3 works normally.
irb(main):001:0> [0b1101001010101101111010100101010011010101010110010101010101010010010101001010101010101011101010101010101111010101010101010101].pack('i')
=> "UU\xBD\xAA"
Upvotes: -1