http://www.perlmonks.org?node_id=355284

Stevie-O has asked for the wisdom of the Perl Monks concerning the following question:

I thought this was a simple problem, but apparently it's tougher than I first thought.

I need to unpack() a pile of data that's in a flexible format. This data has a lot of metadata, e.g. length-of-string, type-of-next-value, etc.. One of the problems is that I don't often know *what* I'm unpacking until I just before need to unpack it.

For example, let's say one of the values was a 'type' byte. 0=byte, 1=short, 2=long, 3=ASCIIZ. I need to do this:

$t = unpack('C', $foo); if ($t == 0) { $v = unpack('C', substr($foo, 1)) } elsif ($t == 1) { $v = unpack('S', substr($foo, 1)) } elsif ($t == 2) { $v = unpack('L', substr($foo, 1)) } elsif ($t == 3) { $v = unpack('Z*', substr($foo, 1)) }
Now, that's not so hard. The problem arises when I have to fetch the NEXT value. For the first three cases it's easy (fixed lengths) but the third is variable-length. How to easily find out the place where unpack() finished, so I can pick up where it left off?

Some might offer 'well, use length($v) + 1 for Z*'. Well, that works for Z*. But what about things like $v = unpack('w', $foo)? 'w' is a variable-length encoded integer value. How do I know whether it was encoded with 1, 2, 3, or 4 bytes? Better yet, try several things - unpack('(wZ*w)5)'

--Stevie-O
$"=$,,$_=q>|\p4<6 8p<M/_|<('=> .q>.<4-KI<l|2$<6%s!<qn#F<>;$, .=pack'N*',"@{[unpack'C*',$_] }"for split/</;$_=$,,y[A-Z a-z] {}cd;print lc