Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

pack/unpack woes

by james289o9 (Acolyte)
on Jun 14, 2022 at 20:50 UTC ( [id://11144736]=perlquestion: print w/replies, xml ) Need Help??

james289o9 has asked for the wisdom of the Perl Monks concerning the following question:

Originally i tried to ask in the chatterbox, but i think that i may have mis-translated what i am trying to do. So without further ado:

I have an ogg/opus audio file that i am trying to read the header, which is 28 bytes or 0x1C in length. Here is the code i am using to read this header:

#!/usr/bin/perl use strict; use warnings; open my $ogg_file, '<', shift or die $!; binmode($ogg_file); read_ogg_header($ogg_file); sub read_ogg_header { my ( $file ) = @_; read($file, my $buf, 28 ); my ( $ogg_magic, $ogg_version, $flags, $granule_position, $serial_ +number, $sequence_number, $checksum, $total_segments, $segment_size ) + = unpack('C4 C1 C1 C8 C4 C4 C4 C1 C1', $buf); print $ogg_magic; ### Expected it to print 'OggS' }
and here is the 28 byte header:
0x4F6767530002000000000000000083CA3DC0000000009F59730A0113

The more i think about this the more i wonder if unpack C is not what i want to do anyway. are the single bytes already in unpack C format? if so, how can i just store that value into the variable without any conversion so any further printing or processing the actual raw values eg print $ogg_magic will print "OggS"

Or maybe i am just completely confused by pack and unpack. i can use read() and i can easily print those values or translate them into expected formats, but i think unpack C is messing me up somehow? or ... OR... maybe i am just completely confused. If i need to elaborate any more please just let me know.

P.S. i guess what i am wondering in the end is, how can i make pack or unpack assign the same values as read($file, my $buf, n);? i can work with whatever data read stores (im assuming binary?) but i cannot get the same values/data to store in those variables with unpack or pack. hope i am clear, if not just give me a swift kick in the hind quarters and tell me what other info you need. and as always any help is certainly appreciated :)

Replies are listed 'Best First'.
Re: pack/unpack woes
by AnomalousMonk (Archbishop) on Jun 14, 2022 at 21:10 UTC

    Win8 Strawberry 5.30.3.1 (64) Tue 06/14/2022 17:01:38 C:\@Work\Perl\monks >perl use strict; use warnings; use Data::Dump qw/dd pp/; my $ogg_head = pack 'H*', '4F6767530002000000000000000083CA3DC0000000009F59730A0113'; dd $ogg_head; # for debug my ($ogg_magic, $opus_version, $flags, $granule_position, $serial_number, $sequence_number, $checksum, $total_segments, $segment_size) = # unpack('C4 C1 C1 C8 C4 C4 C4 C1 C1', $buf); unpack('a4 C C Q N N N C C', $ogg_head); print "'$ogg_magic' \n"; dd $ogg_magic, $opus_version, $flags, $granule_position, $serial_number, $sequence_number, $checksum, $total_segments, $segment_size; printf "%s %02x %02x %08x %04x %04x %04x %02x %02x \n", $ogg_magic, $opus_version, $flags, $granule_position, $serial_number, $sequence_number, $checksum, $total_segments, $segment_size; ^Z pack("H*","4f6767530002000000000000000083ca3dc0000000009f59730a0113") 'OggS' ("OggS", 0, 2, 0, 2211069376, 0, 2673439498, 1, 19) OggS 00 02 00000000 83ca3dc0 0000 9f59730a 01 13
    Note: Check that your version of Perl supports the Q pack/unpack template specifier.


    Give a man a fish:  <%-{-{-{-<

      A little explanation of the changes, with some corrections:

      C4 is the same as C C C C. It extracts 4 numbers.

      $ perl -e'printf "0x%X\n", $_ for unpack "C4", "\x12\x34\x56\x78"' 0x12 0x34 0x56 0x78

      But that's not what you want. You want to extract a single 32-bit unsigned integer in little-endian byte order.[1] After consulting Mini-Tutorial: Formats for Packing and Unpacking Numbers, we determine that we need L< or V for that.

      $ perl -e'printf "0x%X\n", $_ for unpack "L<", "\x12\x34\x56\x78"' 0x78563412

      So, what you want is

      unpack( 'a4 C C Q< L< L< L< C', $ogg_head )

      Note that this is only 27 bytes, not 28. The number of remaining bytes is indicated by that last field (the 27th byte), and may be a number other than one.

      As hinted by the parent, Q is only available on builds of Perl with 64-bit integers (i.e. where perl -V:uvsize aka perl -Mv5.10 -MConfig -e'say $Config{uvsize}' prints 8 or more).


      1. The parent assumed big-endian order and thus used N. But the spec says little-endian byte order is used, which is repeated here.
        I had never read the mini tutorial that you made. After looking at that and then re-reading this comment, everything at least makes sense to me. Not only that, but it actually will help me clean up some code in other modules that ive written. Thanks.
      Thank you AnomalousMonk, this most definitely solves my original question, and gives me some extra things to study.
Re: pack/unpack woes
by ikegami (Patriarch) on Jun 14, 2022 at 20:52 UTC

    Use a4 instead of C4 to get OggS.

      That did the trick. Thank you good sir.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11144736]
Approved by ikegami
Front-paged by ikegami
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (3)
As of 2024-04-25 21:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found