pack and hex

Discussion in 'Perl Misc' started by Larry, Oct 3, 2008.

  1. Larry

    Larry Guest

    Hi,

    before I go into my questions here's a little excerpt from a web site:
    http://www.id3.org/id3v2-00

    "The ID3 tag size is encoded with four bytes where the first bit (bit 7)
    is set to zero in every byte, making a total of 28 bits. The zeroed bits
    are ignored, so a 257 bytes long tag is represented as $00 00 02 01."

    "The reason to use 28 bits (representing up to 256MB) for size
    description is that we don't want to run out of space here."

    I tried to convert 00 00 02 01 from hex to decimal by using my calc and
    it gave me 513 not 257

    In order to get 257 I should have done 00 00 01 01, what am I doing
    wrong?

    is there anyway to have "pack" to get round it?

    Here's a little more from the web site:

    "The three character frame identifier is followed by a three byte size
    descriptor, making a total header size of six bytes in every frame."

    is there anyway to have "pack" to get round this? a number value into 3
    bytes? $00 $00 $00 ??

    thanks ever so much!
    Larry, Oct 3, 2008
    #1
    1. Advertising

  2. Larry

    Larry Guest

    In article <>,
    Larry <> wrote:

    > is there anyway to have "pack" to get round this? a number value into 3
    > bytes? $00 $00 $00 ??


    I tried this and worked well:

    printf "%06X", 1024

    It fred the following:

    000400

    Still I need to divide into 3 bytes: 00 04 00
    Larry, Oct 3, 2008
    #2
    1. Advertising

  3. Larry

    Ben Morrow Guest

    Quoth Larry <>:
    > Hi,
    >
    > before I go into my questions here's a little excerpt from a web site:
    > http://www.id3.org/id3v2-00
    >
    > "The ID3 tag size is encoded with four bytes where the first bit (bit 7)
    > is set to zero in every byte, making a total of 28 bits. The zeroed bits
    > are ignored, so a 257 bytes long tag is represented as $00 00 02 01."
    >
    > "The reason to use 28 bits (representing up to 256MB) for size
    > description is that we don't want to run out of space here."
    >
    > I tried to convert 00 00 02 01 from hex to decimal by using my calc and
    > it gave me 513 not 257


    Yes. You missed the bit that says 'the first bit of every byte is
    ignored'. 00 00 02 01 in binary is

    00000000 00000000 00000010 00000001

    if you the strip the first bit of each byte you get

    0000000 0000000 0000010 0000001

    or 0b100000001 = 257.

    > is there anyway to have "pack" to get round it?


    my $length =
    oct "0b" .
    join "",
    map {
    scalar reverse unpack "b7", $_
    }
    map chr,
    0x00, 0x00, 0x02, 0x01;

    You can probably do it more neatly with vec().

    Ben

    > Here's a little more from the web site:
    >
    > "The three character frame identifier is followed by a three byte size
    > descriptor, making a total header size of six bytes in every frame."
    >
    > is there anyway to have "pack" to get round this? a number value into 3
    > bytes? $00 $00 $00 ??


    What did you try?

    Ben

    --
    It will be seen that the Erwhonians are a meek and long-suffering people,
    easily led by the nose, and quick to offer up common sense at the shrine of
    logic, when a philosopher convinces them that their institutions are not based
    on the strictest morality. [Samuel Butler, paraphrased]
    Ben Morrow, Oct 3, 2008
    #3
  4. Larry

    Larry Guest

    In article <>,
    Ben Morrow <> wrote:

    > > is there anyway to have "pack" to get round it?

    >
    > my $length =
    > oct "0b" .
    > join "",
    > map {
    > scalar reverse unpack "b7", $_
    > }
    > map chr,
    > 0x00, 0x00, 0x02, 0x01;
    >
    > You can probably do it more neatly with vec().


    wow that's great...is there any way to do the reverse function?

    Like, I get an integer number and convert it into a 4-byte-long hex
    string?

    thanks
    Larry, Oct 3, 2008
    #4
  5. Larry

    Ben Morrow Guest

    Quoth Larry <>:
    > In article <>,
    > Ben Morrow <> wrote:
    >
    > > > is there anyway to have "pack" to get round it?

    > >
    > > my $length =
    > > oct "0b" .
    > > join "",
    > > map {
    > > scalar reverse unpack "b7", $_
    > > }
    > > map chr,
    > > 0x00, 0x00, 0x02, 0x01;
    > >
    > > You can probably do it more neatly with vec().

    >
    > wow that's great...is there any way to do the reverse function?
    >
    > Like, I get an integer number and convert it into a 4-byte-long hex
    > string?


    Yes... just reverse each operation.

    Convert to binary: sprintf "%028b", ...
    Split into 7-bit groups: map /(.{7})/g, ...
    Convert back to numbers: map oct("0b" . $_), ...
    Convert to bytes: map chr,
    Join into a string: join "",

    I'll leave you to put the pieces together. (It would have been better to
    use sprintf instead of unpack above; it would be better still to use
    vec() for everything.)

    Is there a good reason you're not using a module like MP3::Tag for this?

    Ben

    --
    "Faith has you at a disadvantage, Buffy."
    "'Cause I'm not crazy, or 'cause I don't kill people?"
    "Both, actually."
    []
    Ben Morrow, Oct 3, 2008
    #5
  6. Larry

    Larry Guest

    In article <>,
    Ben Morrow <> wrote:

    > Is there a good reason you're not using a module like MP3::Tag for this?


    I'm not trying to write/read ID3 tags. Yet, I was struck by the way they
    pack everything into a binary string...

    Right now I cannot figure outhow come they came up with the b7
    thing...If I were to use the following as a b8:

    0xFF 0xFF 0xFF 0xFF

    I could numbers from 0 to 4294967295, with the b7 is a lesser.
    Larry, Oct 3, 2008
    #6
  7. Larry

    Bart Lateur Guest

    Larry wrote:

    >"The ID3 tag size is encoded with four bytes where the first bit (bit 7)
    >is set to zero in every byte, making a total of 28 bits. The zeroed bits
    >are ignored, so a 257 bytes long tag is represented as $00 00 02 01."
    >
    >"The reason to use 28 bits (representing up to 256MB) for size
    >description is that we don't want to run out of space here."
    >
    >I tried to convert 00 00 02 01 from hex to decimal by using my calc and
    >it gave me 513 not 257
    >
    >In order to get 257 I should have done 00 00 01 01, what am I doing
    >wrong?


    You're nto doign anything wrong. 0x00000201 is 513, not 257. But the
    *meaning* of these bytes, using the system they use, is 257.

    You can manually convert the byets to a number accodring to this scheme,
    for example in a loop, effectively treating the bytes as a string
    representation of a number in base 128:

    my $bytes = pack "H*", '00000201';
    my $n = 0;
    foreach my $byte (unpack 'C*', $bytes) {
    $n *= 128;
    $n += 127 & $byte;
    }
    print $n;

    This prints 257.

    An alternative is to use Perl's built in support for BER compressed
    integers, see perlfunc -f pack:

    w A BER compressed integer (not an ASN.1 BER, see
    perlpacktut for details). Its bytes represent an
    unsigned integer in base 128, most significant digit
    first, with as few digits as possible. Bit eight (the
    high bit) is set on each byte except the last.

    That's almost a perfect fit: most significant byte first, base 128, high
    bit not part of the value. So I just need to set the high bit for the
    first 3 bytes (but not for the last), and unpack can directly decode it.
    Let's try that:

    my $bytes = pack "H*", '00000201';
    my $n = unpack "w", $bytes | pack "H*", "80808000";
    print $n;

    That prints 257. Bingo.

    --
    Bart.
    Bart Lateur, Oct 3, 2008
    #7
  8. Larry

    Larry Guest

    In article <>,
    Ben Morrow <> wrote:

    > Is there a good reason you're not using a module like MP3::Tag for this?


    Hi,

    thats what Im trying to do. I have to 2 sockets sending binary data
    each other. I need to have some sort of header on top of the data. I
    cannot read from the socket line by line, I can only sysread. So I
    thought the header would like something like this:

    ($xx is used to indicate a byte with unknown content.)

    HEADER $XX $XX $XX KEY1 $XX $XX VALUE1 KEY2 $XX $XX VALUE2 ...etc...

    - The first 7 bytes of the tag are always "HEADER"
    - The Header size is encoded with 3 bytes
    - Key ID is 4 chars long made out of the characters capital A-Z and 0-9
    - Value size is encoded with 2 bytes
    - Value can contain any kind of data

    So, in a nutshell, Here's what I should do:

    sysread($sock, $header, 10);

    $len = substr $header, 6, 4;

    $len = hex2dec $len

    sysread($sock, $buffer, $len);

    then I can split keys and values accordingly...

    Now i was wondering if it was possible to create a structure like this:

    [ HEADER => [
    KEY1 => VALUE1,
    KEY2 => VALUE2,
    KEY3 => VALUE3
    ]
    ]

    returning a binary strings like this:

    HEADER $XX $XX $XX KEY1 $XX $XX VALUE1 KEY2 $XX $XX VALUE2 KEY3 $xx $xx
    VALUE3
    Larry, Oct 4, 2008
    #8
  9. Larry

    Larry Guest

    Larry, Oct 4, 2008
    #9
  10. Larry

    Bart Lateur Guest

    Larry wrote:

    >Right now I cannot figure outhow come they came up with the b7
    >thing...If I were to use the following as a b8:
    >
    >0xFF 0xFF 0xFF 0xFF
    >
    >I could numbers from 0 to 4294967295, with the b7 is a lesser.


    It's because for MP3, bytes with the high bit set are considered
    special: they're treated as the start of a new audio frame. In
    principle, bytes with the high bit set are illegal in meta tags.

    And then, of course somebody screwed up and put raw Unicode (including
    BOM, which is a 0xFF and a 0xFE byte, indicating byte endianness) in
    ID3v2 meta tags. I know Winamp dares to do that. And now, we're stuck
    with the consequences.

    --
    Bart.
    Bart Lateur, Oct 4, 2008
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    10
    Views:
    6,181
    Neredbojias
    Aug 19, 2005
  2. Bengt Richter
    Replies:
    6
    Views:
    461
    Juha Autero
    Aug 19, 2003
  3. Tim Jones
    Replies:
    0
    Views:
    376
    Tim Jones
    Jan 31, 2004
  4. jack
    Replies:
    4
    Views:
    583
  5. Alexander Farber

    pack 'C3U*' not same as pack 'C3(xC)*'

    Alexander Farber, Jun 23, 2005, in forum: Perl Misc
    Replies:
    2
    Views:
    134
    Ilmari Karonen
    Jun 23, 2005
Loading...

Share This Page