Unpacking Wrong-Endian Signed Shorts/Longs

[email protected] ("Brian de Ford") Sat, 09 Dec 2006 15:43:26 +0000
Newsgroups perl.perlfaq.workers
Message-ID <[email protected]>
Hi 

Once upon a time I had to unpack signed longs in big-endian (network)
format on a little-endian machine.  Because I was in a hurry, and
because I just needed to be sure I understood the file format correctly
at that point, and because I couldn't find a better way of doing it in the
FAQs or with google, I used a horrible kluge. 

Many moons later that proof-of-concept had to be turned into something
usable.  Being a bear of very little brain, I had to think a long time
before the blindingly obvious hit me.  And because it's not in the FAQ
(perhaps because nobody else ever needed to do it) I thought you might
be interested. 

It's an approach that works with little-endian, big-endian or scrambled-
endian (a neologism I just coined for what perlfunc calls "weirder byte
orders") machines without requiring a test for the architecture.  You can 
test for the machine's architecture if you want, and that way you can get
a speed-up if you expect the usual case is right-endian data (or a
slow-down if you expect the usual case is wrong-endian data).  I suspect
that machines with weird sign representations (like ones complement or
sign+magnitude) may give erroneous results, but you can't have everything. 

Assuming the data consists of signed longs in network byte order: 

   @data = unpack('l*', pack('L*', unpack('N*', $data_string))); 

works whether the data is right-endian or wrong-endian.  If the common
case is that the machine has the same endianness as the data then an
architecture test is desirable, using a single unpack for same-endian
data. 

Like I said, blindingly obvious.  But it took me too long to figure it
out, so maybe it's worthy of the FAQ.  OTOH, if worthiness for the FAQ
is based upon me taking a long time to figure it out, you'd also need to
add that it's a good idea for males to unzip their flies and extract their
penises before urinating... :)