pack and hex

L

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

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!
 
L

Larry

Larry said:
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
 
B

Ben Morrow

Quoth Larry said:
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
 
L

Larry

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().[/QUOTE]

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
 
B

Ben Morrow

Quoth Larry said:
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?[/QUOTE]

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
 
L

Larry

Ben Morrow said:
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.
 
B

Bart Lateur

Larry said:
"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.
 
L

Larry

Ben Morrow said:
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
 
B

Bart Lateur

Larry said:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top