Why all the seeks?
Why *not* read the frames when an extended header was found?
Why not use MP3::Tag?
Why not exit if $type is invalid?
I have no knoledge of MP3 and/or MP3-tags at all, but your code looks very very suspiciously wrong. Let me start by posting a simplified version. I only simplified it, because it is a perfect example for something I want to talk about next AmsterdamX.pm meeting :)
The code is not made to work. It is restyled to what I *think* it is supposed to do and I tried to make it a bit more readable/maintainable.
Your version has 219 lines, mine less than half (106) and they did the same on the mp3 files I could find on my system (not that many btw)
use 5.18.2;
use warnings;
sub usage
{
my $err = shift and select STDERR;
say "usage: $0 file.mp3";
exit $err;
} # usage
use Data::Peek;
my $source = shift or usage (1);
@ARGV and usage (1);
open my $in, "<:raw", $source or die "Can not open file '$source': $!\
+n";
say "\nUser has chosen file: $source to open for reading!";
read $in, my $dta, 10;
DHexDump $dta;
# Header 10 Bytes in total 3 Bytes + 1 Byte + 1 Byte + 1 Byte + 4 Byte
+s = 10 Bytes
my ($type, $major_version, $revision_number, $flags, $mp3_size) = unpa
+ck
"A3". # 24 bits (3 Bytes, ASCII text) "ID3". (3 Bytes Heade
+r_ID).
"h". # 8 bits (1 Byte, hex string) Version (1 Byte Major
+_Version).
"h". # 8 bits (1 Byte, hex string) Version (1 Byte Revis
+ion number).
"h". # 8 bits (1 Byte, hex string) Flags (1 Byte Flags
+).
"N", # 32 bits (4 Bytes, Integer), Size (4 Bytes Size)
+.
$dta;
$type =~ m/^[ -~]{3}/ or die "Not a Tagged MP3 file\n";
say "TAG Detected: $type v2.$major_version.$revision_number";
DDumper [ $type, $major_version, $revision_number, $flags, $mp3_size ]
+;
$flags ? say "Flags are not empty, we have found these characters: $fl
+ags\n"
: say "\nThe extended flags has no corresponding data: \$00 was
+ detected. Proceeding!\n\n";
my $length_of_data = $mp3_size;
# say "This is the mp3_size after sync_safe: $mp3_size";
# End of Header
# At this point we want to make sure that we have an extended header (
+ID3v2 flags %abcd0000)
# Bit 7 of (ID3v2 flags %abcd0000) if is 1 (active indicates that ther
+e is extended header
# if is 0 it means there is no extended header. If extended header exi
+st proceed else skip.
if ($flags & 0b01000000) {
# Begging Extended header (Optional not vital for correct parsing)
+.
# Extended Header in tppotal 6 Bytes, size 4 bytes memory size 4 B
+ytes is enough to read binary no characters
# no need for binary to string conversion no need for terminating
+string character ('\0').
# Emptying memory for future use.
read $in, $dta, 6;
my ($extended_size, $number_flags, $extended_flags) = unpack
"N". # 32 bits (4 Bytes) Extended size.
"c". # 8 bits (1 Byte) Flags (1 Byte Flags).
"C", # 8 bits (1 Byte) Extended flags (1 Byte Flags).
$dta;
# Due to Sync_safe remove the 0 from the beggining of each stored
+element and Bitwise,
# although we are working with unsigned characters and integers it
+ is a good practice.
# Synchsafe integers are integers that keep its highest bit (bit 7
+) zeroed, making
# seven bits out of eight available.
say "This is the number of flags: $number_flags";
say "This is the extended header flags: $extended_flags";
say "This is the extended header size, after sync_safe: $extended_
+size";
# From the stored value we substract the Extended Header to get th
+e total size so far.
$length_of_data -= $extended_size;
}
# say "This is the length of data: $length_of_data";
while ($length_of_data) {
# Beginning of Mp3 Frame (10 Bytes in total), 4 Bytes Frame_ID + 4
+ Bytes Frame_Size + 2 Bytes Frame_Flags = 10 Bytes.
# Loop through until the end of length of data previously measured
+.
read $in, $dta, 10 or die "Couldn't read from $source: $!\n";
my ($frame_id, $frame_size, $frame_flags) = unpack
"A4". # 32 bits (4 Bytes) Frame_ID.
"N". # 32 bits (4 Bytes) Frame_Size.
"C2", # 16 bits (2 Bytes) Frame Flags.
$dta;
$length_of_data -= 10 + $frame_size;
print "Third Part Frame id: $frame_id, Frame Size: $frame_size, F
+lags: ";
if ($frame_size) {
read $in, $dta, $frame_size;
if ($frame_id =~ m{^( TPE1 | TALB | TYER | TCON | TRCK )$}) {
say $dta;
next;
}
if ($frame_id eq "TIT2") {
say $dta;
last;
}
}
}
say "\nFinished reading file: $source Closing file! Goodbye!";
close $in or die "Can not close file: $source: $!\n";
Enjoy, Have FUN! H.Merijn