Tim Pease
3/9/2007 2:11:00 AM
On 3/8/07, theosib@gmail.com <theosib@gmail.com> wrote:
> I'm writing a Ruby program that has to process binary data from files
> and sockets. Data items are in bytes, 16-bit words, or 32-bit words,
> and I cannot predict in advance whether the data will be msb-first or
> lsb-first, so I end up writing things like this:
>
> def unpack_16(x)
> @msb_first ? ((x[0]<<8)|x[1]) : ((x[1]<<8)|x[0])
> end
>
> def pack_16(x)
> y = "xx"
> if (@msb_first)
> y[0] = x>>8
> y[1] = x&255
> else
> y[0] = x&255
> y[1] = x>>8
> end
> end
>
> I expect, however, that this will be painfully slow, and I can't
> imagine that this hasn't been though of before. Is there a better way
> to do this that will result in much better performance?
>
def unpack_16( str )
@msb_first ? str.unpack('n') : str.unpack('S')
end
def pack_16( num )
@msb_first ? [num].pack('n') : [num].pack('S')
end
That will work for little-endian processors (Intel) but not for
big-endian processors (PowerPC, Sparc). For these methods to work on
the latter you'll have to do something like this ...
def unpack_16( str )
str = str.reverse unless @msb_first
str.unpack('n')
end
def pack_16( num )
str = [num].pack('n')
str.reverse unless @msb_first
end
Just define the desired method based on the processor type -- which
can be figued out by doing this ...
LITTLE_ENDIAN = [42].pack('I')[0] == 42
if LITTLE_ENDIAN
# define little endian methods here
else
# define big endian methods here
end
Hope that helps
Blessings,
TwP